uglifyjs壓縮JS的


一、故事總有其背景

年末將至,很多閑適的時間,於是刷刷微博,接觸各種紛雜的信息——美其名曰“學習”。運氣不錯,遇到了一個新名詞,uglifyjs. 據說是用來壓縮JS文件的,據說還能優化JS,據說是基於node的,還據說比Google Closure Compiler更帶感,哦?激起了我的好奇心。百之谷之,喲,相關的介紹還不少。然后折騰了個把小時,基本上知道了是個怎么回事。

我覺得吧,還是有些用的,即使是不是從事node開發的人,抽個小空,share之,於是就有了本文。人總有浮躁的時候,我也不例外,uglifyjs內部深入的運作是如何的,唉,我是有氣無力,不想去折騰,所以,本文更多是停留在應用層面。不過嘛,這樣反而受眾面廣一些。畢竟喜歡看《泰囧》的人要比《一代宗師》的多。

二、node相關的固定流程

凡事提及node應用,無非免不了類似下面的流程:

  1. 安裝node
  2. 安裝nmpnpm
  3. 安裝當前應用 – uglifyjs

前兩個網上太多示意了,我之前也講過,sorry, 我很懶。
uglifyjs安裝如下code:

npm install uglify-js -g

一個回車,於是啪啪啪,就有下圖所示的東東:
uglifyjs安裝顯示截圖 張鑫旭-鑫空間-鑫生活

於是,下面就可以壓縮JS了。

三、uglifyjs JS壓縮

uglifyjs壓縮有很多的參數,詳見其github托管項目。其中有一些可選參數,如下部分截圖:
uglifyjs的一些可選參數截圖

什么美化壓縮,空格多長,變量名是否變成短名字等……您有興趣可以自己去看看,如果今天不是星期五,如果不是要趕回去買菜,我就會翻譯下的——諸位,請原諒我吧,阿門!

下面演示如何使用uglifyjs壓縮JS.

我的桌面上有個名叫formini的文件夾,我會把要壓縮的文件放在其中,然后再壓縮。現在,我從內部拷貝了一個名叫inet.js的JS文件到這個文件夾中,然后:

  1. 打開cmd, 這個不會我就沒有辦法了
  2. 目錄引到formini文件夾,cd 然后什么什么的,這個不會我也沒有辦法了
  3. 如下代碼:
    uglifyjs inet.js -o inet-min.js
  4. 再運行如下代碼,測試-m可選參數:
    uglifyjs inet.js -m -o inet.min.js

    如下截圖:
    壓縮運行代碼

噢啦,現在就是看結果了,見下截圖:
壓縮后的JS文件大小 張鑫旭-鑫空間-鑫生活

90K的是沒有運行-m參數的,70K(69.4)的是運行的。-m參數所以就是把變量名變成a, b, c, d, ...

從實際應用角度講,上線的JS顯然要壓縮變量,減小一定的文件尺寸。

跟YUICompressor相比,大小只小了0.6K, 不過網上反映uglifyjs相比YUI壓縮很明顯,我這里的大小僅優化了0.6÷174=0.345%,這只能說明我寫的代碼還算比較優化,哈哈(突然想起了老婆的話,不要得瑟,深呼吸……深呼吸……)!
YUICompressor壓縮后的大小

四、uglifyjs壓縮批處理

我們不可能每次都打開cmd去鍵入壓縮執行代碼,容易寫錯不說(如上面那個結果圖),還耗時,想想都會讓人瘋掉。懶人有懶法,花了點功夫,折騰了一個批處理文件,以后,想要壓縮JS,只要雙擊運行這個.bat文件就可以了!完整代碼如下:

@echo off
:: 設置壓縮JS文件的根目錄,腳本會自動按樹層次查找和壓縮所有的JS
SET JSFOLDER=C:\Users\Administrator\Desktop\formini
echo 正在查找JS文件
chdir /d %JSFOLDER%
for /r . %%a in (*.js) do (
    @echo 正在壓縮 %%~a ...
    uglifyjs %%~fa  -m -o %%~fa
)
echo 完成!
pause & exit

新建一個txt文檔,任意命名,將上面的代碼粘貼進去,修改JSFOLDER后面的文件夾目錄為你自己的,然后把.txt后綴改成.bat就可以啦!然后雙擊就可以批量使用uglifyjs壓縮JS文件啦!

四、結束語

對於自己來講,本文內容算作備忘。目前而言,我還是uglifyjs不能壓縮CSS文件。不過嘛,了解下總會有幫助的。行文匆忙,文中要是有表述不准確的地方歡迎指正。

 

另外一篇文章介紹

前言

做Web前端開發,總是要考慮頁面的打開速度,如果文件數量越少、文件長度越小,就可以直接的提升網頁的訪問速度。

但在開發的時候,為了保證代碼的可讀性,我們寫的程序文件會很多而且很大,這樣就與部署的要求發生背離,通過UglifyJS2這個工具,我們可以在開發完成時,對代碼文件進行 合並、混淆、壓縮 等的操作,達到最優的訪問性能。

目錄

  1. UglifyJS介紹
  2. UglifyJS2介紹
  3. UglifyJS2安裝
  4. UglifyJS2命令操作
  5. UglifyJS2的API使用

1. UglifyJS介紹

開始UglifyJS2介紹之前,我們先要說一下UglifyJS。 UglifyJS 是UglifyJS2的前身,是一個Javascript開發的通用的語法分析、代碼壓縮、代碼優化的一個工具包。UglifyJS是基於Nodejs環境開發,支持CommonJS模塊系統的任意的Javascript平台。

UglifyJS的實現主要分為2部分:

  • 生成JS代碼的抽象語法樹(AST),通過parse-js.js完成。
  • 遍歷AST語法樹,做各種操作,比如自動縮進、縮短變量名、刪除塊括號{}、去空格、常量表達式、連續變量聲明、語塊合並、去掉無法訪問的代碼等,通過process.js完成。

2. UglifyJS2介紹

UglifyJS2 是作者對UglifyJS的重寫,是完全的重寫,而不僅僅是升級。從UglifyJS2官司方網頁介紹看,UglifyJS2把整個的JS壓縮過程,做了更進一步的細化。

上述所有的功能代碼API是 在6500行的左右,比其他的相同功能的開發包都要小。作者還提供了一個在線版本UglifyJS2的JS壓縮工具, http://lisperator.net/uglifyjs/,大家可以測試一下。

3. UglifyJS2安裝

系統環境:

  • win7 64bit
  • Nodejs:v0.10.5
  • Npm:1.2.19

UglifyJS2的安裝非常簡單,和Nodejs的其他包一樣,全局安裝使用如下命令。

npm install uglify-js -g

也可以通過github下載源代碼安裝。


git clone git://github.com/mishoo/UglifyJS2.git cd UglifyJS2 

我們在使用UglifyJS2的時候主要有2種方式,一種是通過命令行操作,對指定的JS文件進行壓縮;另一種是通過程序的API調用,對文件或內存中的JS代碼進行壓縮。下面我將分兩種情況進行介紹。

4. UglifyJS2命令操作

在全局安裝好UglifyJS2以后,我們就可以使用UglifyJS2的命令了。

打印uglifyjs命令行的幫助信息,會打出很長一段說明。


D:\workspace\javascript\nodejs-uglifyJS2>uglifyjs -h
D:\toolkit\nodejs\\node.exe D:\toolkit\nodejs\node_modules\uglify-js\bin\uglifyjs input1.js [input2.js ...] [options]
Use a single dash to read input from the standard input.

NOTE: by default there is no mangling/compression.
Without [options] it will simply parse input files and dump the AST
with whitespace and comments discarded.  To achieve compression and
mangling you need to use `-c` and `-m`.

Options:
  --source-map Specify an output file where to generate source map. [string] --source-map-root The path to the original source to be included in the source map. [string] --source-map-url The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map. [string] --source-map-include-sources Pass this flag if you want to include the content of source files in the source map as sourcesContent property. [boolean] --in-source-map Input source map, useful if you're compressing JS that was generated from some other original code. --screw-ie8 Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks (by default UglifyJS will try to be IE-proof). [boolean] --expr Parse a single expression, rather than a program (for parsing JSON) [boolean] -p, --prefix Skip prefix for original filenames that appear in source maps. For example -p 3 will drop 3 directories from file names and ensure they are relative paths. You can also specify -p relative, which will make UglifyJS figure out itself the relative paths between original sources, the source map and the output file. [string] -o, --output Output file (default STDOUT). -b, --beautify Beautify output/specify output options. [string] -m, --mangle Mangle names/pass mangler options. [string] -r, --reserved Reserved names to exclude from mangling. -c, --compress Enable compressor/pass compressor options. Pass options like -c hoist_vars=false,if_return=false. Use -c with no argument to use the default compression options. [string] -d, --define Global definitions [string] -e, --enclose Embed everything in a big function, with a configurable parameter/argument list. [string] --comments Preserve copyright comments in the output. By default this works like Google Closure, keeping JSDoc-style comments that contain "@license" or "@preserve". You can optionally pass one of the following arguments to this flag: - "all" to keep all comments - a valid JS regexp (needs to start with a slash) to keep only comments that match. Note that currently not *all* comments can be kept when compression is on, because of dead code removal or cascading statements into sequences. [string] --preamble Preamble to prepend to the output. You can use this to insert a comment, for example for licensing information. This will not be parsed, but the source map will adjust for its presence. --stats Display operations run time on STDERR. [boolean] --acorn Use Acorn for parsing. [boolean] --spidermonkey Assume input files are SpiderMonkey AST format (as JSON). [boolean] --self Build itself (UglifyJS2) as a library (implies --wrap=UglifyJS --export-all) [boolean] --wrap Embed everything in a big function, making the “exports” and “global” variables available. You need to pass an argument to this option to specify the name that your module will take when included in, say, a browser. [string] --export-all Only used when --wrap, this tells UglifyJS to add code to automatically export all globals. [boolean] --lint Display some scope warnings [boolean] -v, --verbose Verbose [boolean] -V, --version Print version number and exit. [boolean] --noerr Don't throw an error for unknown options in -c, -b or -m. [boolean] 

對命令參數進行解釋:

  • –source-map [string],生成source map文件。
  • –source-map-root [string], 指定生成source map的源文件位置。
  • –source-map-url [string], 指定source map的網站訪問地址。
  • –source-map-include-sources,設置源文件被包含到source map中。
  • –in-source-map,自定義source map,用於其他工具生成的source map。
  • –screw-ie8, 用於生成完全兼容IE6-8的代碼。
  • –expr, 解析一個表達式或JSON。
  • -p, –prefix [string], 跳過原始文件名的前綴部分,用於指定源文件、source map和輸出文件的相對路徑。
  • -o, –output [string], 輸出到文件。
  • -b, –beautify [string], 輸出帶格式化的文件。
  • -m, –mangle [string], 輸出變量名替換后的文件。
  • -r, –reserved [string], 保留變量名,排除mangle過程。
  • -c, –compress [string], 輸出壓縮后的文件。
  • -d, –define [string], 全局定義。
  • -e, –enclose [string], 把所有代碼合並到一個函數中,並提供一個可配置的參數列表。
  • –comments [string], 增加注釋參數,如@license、@preserve。
  • –preamble [string], 增加注釋描述。
  • –stats, 顯示運行狀態。
  • –acorn, 用Acorn做解析。
  • –spidermonkey, 解析SpiderMonkey格式的文件,如JSON。
  • –self, 把UglifyJS2做為依賴庫一起打包。
  • –wrap, 把所有代碼合並到一個函數中。
  • –export-all, 和–wrap一起使用,自動輸出到全局環境。
  • –lint, 顯示環境的異常信息。
  • -v, –verbose, 打印運行日志詳細。
  • -V, –version, 打印版本號。
  • –noerr, 忽略錯誤命令行參數。

通過對命令行各種參數的解釋,我們基本上知道了這些參數都是干什么的了,下面我就試一下。

寫2個簡單地JS文件,demo.js, main.js。


~ vi D:\workspace\javascript\nodejs-uglifyJS2\demo.js

'use strict'; function hello(name){  if(name==='fens.me'){   return "Long time no see, "+name;  }  return "hello "+name; } console.log(hello('Conan')); console.log(hello('fens.me')); 

main.js


~ vi D:\workspace\javascript\nodejs-uglifyJS2\main.js

'use strict'; function book(){ return [ {head:'前言',page:'/views/tpl/book-r1/preface.html',active:false}, {head:'目錄',page:'/views/tpl/book-r1/contents.html',active:true}, {head:'代碼',page:'/views/tpl/book-r1/code.html',active:false}, {head:'試讀',page:'/views/tpl/book-r1/sample.html',active:false}, {head:'勘誤',page:'/views/tpl/book-r1/mistake.html',active:false} ]; } var tab=function(arr,idx){  for(var i=0;i<arr.length;i++){   arr[i].active = (idx==i?true:false);  }  return arr; } console.log(tab(book(),3)); 

接下來,用UglifyJS2命令進行操作,合並兩個文件,對變量名用單字母替換,進行壓縮,所有代碼合並到一個函數,生成source map,指定source map來源網站。


D:\workspace\javascript\nodejs-uglifyJS2>uglifyjs main.js demo.js -o foo.min.js --source-map foo.min.js.map --source-map-root http://onbook.me -p 5 -c -m --wrap --export-all 

在當前目錄生成了2個新文件:foo.min.js.map, foo.min.js,分別查看這兩個文件。

foo.min.js


!function(e,t){"use strict";function o(){return[{head:"前言",page:"/views/tpl/book-r1/preface.html",active:!1},{head:"目錄",page:"/views/tpl/book-r1/contents.html",active:!0},{head:"代碼",page:"/views/tpl/book-r1/code.html",active:!1},{head:"試讀",page:"/views/tpl/book-r1/sample.html",active:!1},{head:"勘誤",page:"/views/tpl/book-r1/mistake.html",active:!1}]}function n(e){return"fens.me"===e?"Long time no see, "+e:"hello "+e}t["true"]=e,console.log(a(o(),3));var a=function(e,t){for(var o=0;o 

foo.min.js.map


{"version":3,"file":"foo.min.js","sources":["?"],"names":["exports","global","book","head","page","active","hello","name","console","log","tab","arr","idx","i","length","this"],"mappings":"CAAC,SAASA,EAASC,GAAnB,YAEA,SAASC,KACL,QACKC,KAAK,KAAKC,KAAK,kCAAkCC,QAAO,IACxDF,KAAK,KAAKC,KAAK,mCAAmCC,QAAO,IACzDF,KAAK,KAAKC,KAAK,+BAA+BC,QAAO,IACrDF,KAAK,KAAKC,KAAK,iCAAiCC,QAAO,IACvDF,KAAK,KAAKC,KAAK,kCAAkCC,QAAO,IANjE,QAASC,GAAMC,GACd,MAAU,YAAPA,EACK,qBAAqBA,EAEtB,SAASA,EANWN,EAAO,QAAUD,EAY7CQ,QAAQC,IAAIC,EAAIR,IAAO,GADvB,IAAIQ,GAAI,SAASC,EAAIC,GACpB,IAAI,GAAIC,GAAE,EAAEA,EAAEF,EAAIG,OAAOD,IACxBF,EAAIE,GAAGR,OAAUO,GAAKC,GAAE,GAAK,CAE9B,OAAOF,GAGRH,SAAQC,IAAIH,EAAM,UAClBE,QAAQC,IAAIH,EAAM,mBAjBTJ,UAAAI,QASLI,MAX8E,WAAW,MAAOK","sourceRoot":"http://onbook.me"} 

通過一條簡單的命令,就實現了對JS代碼的合並、壓縮等的操作,確實非常方便。

下載jquery-2.1.1.js文件自己壓縮,並與官方的壓縮文件進行對比。


# 下載 ~ wget http://code.jquery.com/jquery-2.1.1.js ~ wget http://code.jquery.com/jquery-2.1.1.min.js # 壓縮 ~ uglifyjs jquery-2.1.1.js -o jquery-2.1.1.min.uglifyjs2.js -p 5 -c -m # 比較3個文件大小 ~ ls -l -rwx------ 1 4294967295 mkpasswd 247351 Jul 6 16:26 jquery-2.1.1.js -rwx------ 1 4294967295 mkpasswd 84245 Jul 6 16:32 jquery-2.1.1.min.js -rwx------ 1 4294967295 mkpasswd 84113 Jul 6 16:28 jquery-2.1.1.min.uglifyjs2.js 

我在本地壓縮的文件jquery-2.1.1.min.uglifyjs2.js,與jquery官司網下載的壓縮文件jquery-2.1.1.min.js大小差不多,都在84KB左右。

5. UglifyJS2的API使用

另一種使用方式是,把UglifyJS2包放到程序中,通過API對JS文件或JS代碼進行壓縮。首先,新建一個NPM項目文件package.json,然后在是下載UglifyJS2依賴包。

新建文件package.json


~ vi D:\workspace\javascript\nodejs-uglifyJS2\package.json { "name": "nodejs-uglifyjs2", "version": "0.0.1", "description": "uglifyjs2", "author": "Conan Zhang ", "dependencies": { } } 

下載UglifyJS2依賴包


D:\workspace\javascript\nodejs-uglifyJS2>npm install uglify-js --save npm WARN package.json nodejs-uglifyjs2@0.0.1 No readme data! npm http GET https://registry.npmjs.org/uglify-js npm http 304 https://registry.npmjs.org/uglify-js npm http GET https://registry.npmjs.org/async npm http GET https://registry.npmjs.org/source-map npm http GET https://registry.npmjs.org/optimist npm http GET https://registry.npmjs.org/uglify-to-browserify npm http 304 https://registry.npmjs.org/uglify-to-browserify npm http 304 https://registry.npmjs.org/optimist npm http 304 https://registry.npmjs.org/async npm http 304 https://registry.npmjs.org/source-map npm http GET https://registry.npmjs.org/wordwrap npm http GET https://registry.npmjs.org/amdefine npm http 304 https://registry.npmjs.org/wordwrap npm http 304 https://registry.npmjs.org/amdefine uglify-js@2.4.14 node_modules\uglify-js ├── uglify-to-browserify@1.0.2 ├── async@0.2.10 ├── optimist@0.3.7 (wordwrap@0.0.2) └── source-map@0.1.34 (amdefine@0.1.0) 

我們新建一個文件uglify2.js,用於編寫程序。


~ vi D:\workspace\javascript\nodejs-uglifyJS2\uglify2.js

'use strict'; var UglifyJS = require('uglify-js'); //代碼壓縮 var result = UglifyJS.minify("var b = function () {};", {fromString: true}); console.log("\n==========================="); console.log(result); //文件壓縮 result = UglifyJS.minify(["demo.js"]); console.log("\n==========================="); console.log(result.code); //多文件壓縮,指定source map和網站來源 result = UglifyJS.minify(["main.js","demo.js"],{ outSourceMap: "out.js.map", sourceRoot: "http://onbook.me", mangle:true }); console.log("\n==========================="); console.log(result.code); console.log(result.map); 

程序輸出:


D:\workspace\javascript\nodejs-uglifyJS2>node uglify2.js

===========================
{ code: 'var b=function(){};', map: 'null' } =========================== "use strict";function hello(e){return"fens.me"===e?"Long time no see, "+e:"hello "+e}var tab=function(e,o){for(var n=0;n <e.length;n++)e[n].active=o==n?!0:!1;return e};console.log(hello("Conan")),console.log(hello("fens.me")); =========================== "use strict";function book(){return[{head:"前言",page:"/views/tpl/book-r1/preface.html",active:!1},{head:"目錄",page:"/v iews/tpl/book-r1/contents.html",active:!0},{head:"代碼",page:"/views/tpl/book-r1/code.html",active:!1},{head:"試讀",page :"/views/tpl/book-r1/sample.html",active:!1},{head:"勘誤",page:"/views/tpl/book-r1/mistake.html",active:!1}]}function he llo(e){return"fens.me"===e?"Long time no see, "+e:"hello "+e}console.log(tab(book(),3));var tab=function(e,o){for(var t= 0;t<e.length;t++)e[t].active=o==t?!0:!1;return e};console.log(hello("Conan")),console.log(hello("fens.me")); //# sourceMappingURL=out.js.map {"version":3,"file":"out.js.map","sources":["main.js","demo.js"],"names":["book","head","page","active","hello","name"," console","log","tab","arr","idx","i","length"],"mappings":"AAAA,YAEA,SAASA,QACL,QACKC,KAAK,KAAKC,KAAK,kCAAkCC,QAAO,IACxD F,KAAK,KAAKC,KAAK,mCAAmCC,QAAO,IACzDF,KAAK,KAAKC,KAAK,+BAA+BC,QAAO,IACrDF,KAAK,KAAKC,KAAK,iCAAiCC,QAAO,IACvDF,KAAK,KAAKC ,KAAK,kCAAkCC,QAAO,ICNjE,QAASC,OAAMC,GACd,MAAU,YAAPA,EACK,qBAAqBA,EAEtB,SAASA,EDMjBC,QAAQC,IAAIC,IAAIR,OAAO,GCDvB,IAAIQ, KAAI,SAASC,EAAIC,GACpB,IAAI,GAAIC,GAAE,EAAEA,EAAEF,EAAIG,OAAOD,IACxBF,EAAIE,GAAGR,OAAUO,GAAKC,GAAE,GAAK,CAE9B,OAAOF,GAGR H,SAAQC,IAAIH,MAAM,UAClBE,QAAQC,IAAIH,MAAM","sourceRoot":"http://onbook.me"} 

我們看到用操作uglifyJS2包的API,還是挺簡單的,如果對AST樹有遍歷需求,API提供了非常實用的函數支持。

不過我在測試API過程中,發現有2個問題。

  • 通過API設置mangle選項,但輸出沒有效果。
  • 沒有--wrap和--export-all 命令行參數對應的API。

通過本文的介紹,我們基本上了解了uglifyJS2包的功能和使用方法,然后就可以放心大膽地對JS代碼進行壓縮了。在實際的前端項目中,一般不用自己配置uglifyJS2包,而是通過grunt來調用uglifyJS2進行代碼發布前的壓縮,關於grunt使用,請參考文章: grunt讓Nodejs規范起來 。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM