用UglifyJS解析/壓縮/格式化你的Javascript

來源:互聯網
上載者:User
文章目錄
  • 涉及到全域數組建構函式的調用 
  • 通過NPM安裝 
  • 通過GitHub安裝最新版本 

UglifyJS是基於 NodeJS 的Javascript文法解析/壓縮/格式化工具,它支援任何CommonJS模組系統的Javascript平台(實現自己的CommonJS平台也非難事)。 UglifyJS通過解析重建JS代碼的文法樹,你可以通過AST以瞭解更多代碼情況,或者自己來做一個不同的實現。UglifyJS解析器是在 parse-js.js 中實現的,它是非常優秀的 parse。

 非安全轉換

UglifyJS是基於 NodeJS 的Javascript文法解析/壓縮/格式化工具,它支援任何CommonJS模組系統的Javascript平台(實現自己的CommonJS平台也非難事)。

UglifyJS通過解析重建JS代碼的文法樹,你可以通過AST以瞭解更多代碼情況,或者自己來做一個不同的實現。UglifyJS解析器是在 parse-js.js 中實現的,它是非常優秀的 parse-js Common Lisp Library 的一部分。

(如果你正在尋找UglifyJS的Common Lisp版本,點擊 這裡 )

UglifyJS的另一個重要部分是在 process.js 實現的,它用於檢查並實現解析產生的AST: 

    • 通過AST進行Javascript代碼的重建 :如果你想格式化已經被壓縮過的代碼,可以選擇縮排參數。你也可以列印出無空白(whitespace)的AST,以達到壓縮的目的。
    • 縮短變數名 :UglifyJS通過分析代碼並產生新的變數名稱,依賴於範圍,這些名稱通常被簡化為單一字元,並能足夠智能的處理全域變數,或者eval()調用及with{}塊。換句話說,如果在某個範圍內使用了eval()或with{},那麼該範圍的所有變數及其父範圍的變數都不會被重新命名,並且所有指向這類變數的引用也不會被改變。
    • 以下是一些最佳化規則會讓代碼更簡潔更高效 : 
        • foo["bar"] ==> foo.bar
        • 刪除塊標記{}
        • 合并變數聲明: var a = 10; var b = 20; ==> var a=10,b=20;
        • 計算簡單的常量運算式:1 + 2 * 3 ==> 7. UglifyJS只替換計算結果比實際運算式位元組更少的情況;比如 1/3 結果為 0.333333333333,因此不會被替換。
        • 連續的語句塊會被合并為一個序列;大多情況下,這將保留一個語句,接下來塊括弧可以被移除。
        • IF語句的最佳化 : 
            • if (foo) bar(); else baz(); ==> foo?bar():baz();
            • if (!foo) bar(); else baz(); ==> foo?baz():bar();
            • if (foo) bar(); ==> foo&&bar();
            • if (!foo) bar(); ==> foo||bar();
            • if (foo) return bar(); else return baz(); ==> return foo?bar():baz();
            • if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} 
        • 移除不會被用到的代碼並會給出警告。 
非安全轉換

UglifyJS在保留語義的同時會盡量提高壓縮比率,如果經過UglifyJS處理後你的代碼邏輯失效了,或對UglifyJS的最佳化實現有更好的想法,都可有直接聯絡作者。 

涉及到全域數組建構函式的調用 

這時會進行如下轉換:

newArray(1,2,3,4)=>[1,2,3,4]Array(a, b, c)=>[a,b,c]newArray(5)=>Array(5)newArray(a)=>Array(a)

在Array沒有被重新定義之前,這些轉換是安全的。UglifyJS也會對經過使用者本地或全域重定義的Array進行處理,但CSSer建議還是不要這麼做:

// case 1.  全域聲明varArray;newArray(1,2, www.csser.com);Array(a, b);// 或者後聲明newArray(1,2,3);varArray;// 或者定義為函數newArray(1,2,3);functionArray(){...}// case 2. 在函數內部聲明(function(){    a =newArray(1,2,3);    b =Array(5,6);varArray;})();// 或者(function(Array){returnArray(5,6,7);})();// 或者(function(){returnnewArray(1,2,3,4);functionArray(){...}})();

// 等等.

安裝 通過NPM安裝 

UglifyJS已經可以通過NPM進行安裝:

npm install uglify-js 
通過GitHub安裝最新版本 
## 複製倉庫mkdir -p /where/you/wanna/put/itcd /where/you/wanna/put/itgit clone git://github.com/mishoo/UglifyJS.git## 讓uglify模組對NodeJS有效mkdir -p ~/.node_libraries/cd ~/.node_libraries/ln -s /where/you/wanna/put/it/UglifyJS/uglify-js.js## 支援命令列的方式調用mkdir -p ~/bincd ~/binln -s /where/you/wanna/put/it/UglifyJS/bin/uglifyjs  # (然後將 ~/bin 增加到 $PATH)
如何使用

UglifyJS提供了命令列工具,支援shell指令碼的操作需要:

uglifyjs [選項...][檔案名稱]

最後一個參數是要處理的JS檔案名稱,如果不指定,則從標準輸入(STDIN)讀取。

支援的選項 :

    • -b 或 --beautify - 輸出格式化代碼,當傳入該參數,下面的附加選項用於更美觀的控制格式化: 

        • -i N 或 --indent N - 縮排層級(空格數量)
        • -q 或 --quote-keys - 是否用引號引起字串對象的鍵(預設只會引起不能被正確標誌的鍵名) 
    • --ascii -預設 UglifyJS 不處理字元編碼而直接輸出 Unicode 字元,通過傳入該參數將非ASCII編碼的字元轉化為\cXXXX的序列(輸出總按照UTF8編碼,但傳入該選項能得到ASCII編碼的輸出)。
    • -nm 或 --no-mangle - 不改變變數名稱
    • -ns 或 --no-squeeze - 不調用 ast_squeeze() 函數(該函數會做多種最佳化使得結果更小,可讀性略有降低)
    • -mt 或 --mangle-toplevel - 在頂級範圍打亂變數名稱(預設不開啟)
    • --no-seqs - 當調用 ast_squeeze() 將會合并多個語句塊為一個語句塊,如 "a=10; b=20; foo()" 將被轉換為 "a=10,b=20,foo()"
    • --no-dead-code - 預設 UglifyJS 將會刪除不被用到的代碼,傳入該參數禁用此功能。
    • -nc 或 --no-copyright - 預設 uglifyjs 會在輸出後的代碼中添加著作權資訊等注釋代碼,傳入該參數禁用此功能。
    • -o 檔案名稱 或 --output 檔案名稱 - 指定輸出檔案名,如果不指定,則列印到標準輸出(STDOUT)
    • --overwrite - 如果傳入的JS代碼來自檔案而不是標準輸入,傳入該參數,輸出會覆蓋該檔案。
    • --ast - 傳入該參數會得到抽象的文法樹而不是Javascript,對調試或瞭解內部代碼很有用。
    • -v 或 --verbose - 在標準錯誤輸出一些資訊(目前的版本僅輸出操作用時)
    • --extra - 開啟附加最佳化,這些最佳化並未得到全面的測試。
    • --unsafe - 開啟其他附加最佳化,這些最佳化已知在特定情況下並不安全,目前僅支援: 
        • foo.toString() ==> foo+”” 
    • --max-line-len (預設32K位元組) - 在32K位元組出增加分行符號,傳入0禁用此功能。
    • --reserved-names - 一些類庫會依賴一些變數,該參數指定的名稱不會被混淆掉,多個用逗號隔開。 
API

要想在Javascript中使用UglifyJS類庫,參考下面的樣本(以NodeJS為例):

var jsp =require("uglify-js").parser;var pro =require("uglify-js").uglify;var orig_code ="Javascript代碼";var ast = jsp.parse(orig_code);// 解析代碼返回初始的ASTast = pro.ast_mangle(ast);// 擷取變數名稱打亂的ASTast = pro.ast_squeeze(ast);// 擷取經過壓縮最佳化的ASTvar final_code = pro.gen_code(ast);// 壓縮後的代碼

上面的代碼會立刻進行代碼的全面壓縮,正如你所看到的,這裡經曆了一系列的步驟,你可有省略某些步驟以滿足自己的需求。

這裡的函數有一些參數,我們做些介紹: 

    • jsp.parse(code, strict_semicolons) - 解析JS代碼並返回AST。strict_semicolons是可選的,預設為false,當傳入true,解析器會在預期為分號而實際沒找到的情況下拋出錯誤。對於大多數JS代碼我們不需要那麼做,但嚴格約束代碼很有益處。
    • pro.ast_mangle(ast, options) - 返回經過變數和函數名稱混淆的AST,它支援以下選項: 
        • toplevel - 混淆頂級範圍的變數和函數名稱(預設不開啟)。
        • except - 指定不被壓縮的名稱的數組 
    • pro.ast_squeeze(ast, options) - 開啟深度最佳化以降低代碼尺寸,返回新的AST,選項可以是一個hash,支援的參數有: 
        • make_seqs (預設true) 將多個語句塊合并為一個。
        • dead_code (預設true) 將刪除不被使用的代碼。 
    • pro.gen_code(ast, options) - 通過AST產生JS代碼。預設輸出壓縮代碼,但可以通過調整選項參數獲得格式化的輸出。選項是可選的,如果傳入必須為對象,支援以下選項: 
        • beautify: false - 如果希望得到格式化的輸出,傳入true
        • indent_start: 0 (僅當beautify為true時有效) - 初始縮排空格
        • indent_level: 4 (僅當beautify為true時有效) - 縮排層級,空格數量
        • quote_keys: false - 傳入true將會用引號引起所有文字物件的key
        • space_colon: false (僅當beautify為true時有效) - 是否在冒號前保留空格
        • ascii_only: false - 傳入true則將編碼非ASCII字元到\uXXXX 
結語

UglifyJS在文法上與Google壓縮相似,在效能上是一流的,所以建議多多實踐!

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.