javascript
[转载]用UglifyJS2合并压缩混淆JS代码——javascript系列
從零開始nodejs系列文章,將介紹如何利Javascript做為服務端腳本,通過Nodejs框架web開發。Nodejs框架是基于V8的引擎,是目前速度最快的Javascript引擎。chrome瀏覽器就基于V8,同時打開20-30個網頁都很流暢。Nodejs標準的web開發框架Express,可以幫助我們迅速建立web站點,比起PHP的開發效率更高,而且學習曲線更低。非常適合小型網站,個性化網站,我們自己的Geek網站!!
關于作者
- 張丹(Conan), 程序員Java,R,PHP,Javascript
- weibo:@Conan_Z
- blog:?http://blog.fens.me
- email: bsspirit@gmail.com
轉載請注明出處:
http://blog.fens.me/nodejs-uglifyjs2-js/
前言
做Web前端開發,總是要考慮頁面的打開速度,如果文件數量越少、文件長度越小,就可以直接的提升網頁的訪問速度。
但在開發的時候,為了保證代碼的可讀性,我們寫的程序文件會很多而且很大,這樣就與部署的要求發生背離,通過UglifyJS2這個工具,我們可以在開發完成時,對代碼文件進行 合并、混淆、壓縮 等的操作,達到最優的訪問性能。
目錄
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壓縮過程,做了更進一步的細化。
- parser,用于實現抽象語言法樹(AST)。
- the code generator, 通過AST生成JS代碼和source map。
- compressor, 用于JS代碼的壓縮。
- mangler, 用于減少局部變量的命名,用單字母替換。
- scope analyzer, 用來判斷 變量定義范圍和變量引用范圍的工具。
- tree walker, AST樹遍歷工具。
- tree transformer, AST樹轉換工具。
上述所有的功能代碼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 sourcemap. [string]--source-map-root The path to the original source to be includedin the source map. [string]--source-map-url The path to the source map to be added in //#sourceMappingURL. Defaults to the value passedwith --source-map. [string]--source-map-include-sources Pass this flag if you want to include thecontent of source files in the source map assourcesContent property. [boolean]--in-source-map Input source map, useful if you're compressingJS that was generated from some other originalcode.--screw-ie8 Pass this flag if you don't care about fullcompliance with Internet Explorer 6-8 quirks(by default UglifyJS will try to be IE-proof).[boolean]--expr Parse a single expression, rather than aprogram (for parsing JSON) [boolean]-p, --prefix Skip prefix for original filenames that appearin source maps. For example -p 3 will drop 3directories from file names and ensure they arerelative paths. You can also specify -prelative, which will make UglifyJS figure outitself the relative paths between originalsources, 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. Passoptions like -choist_vars=false,if_return=false. Use -c withno argument to use the default compressionoptions. [string]-d, --define Global definitions [string]-e, --enclose Embed everything in a big function, with aconfigurable parameter/argument list. [string]--comments Preserve copyright comments in the output. Bydefault this works like Google Closure, keepingJSDoc-style comments that contain "@license" or"@preserve". You can optionally pass one of thefollowing arguments to this flag:- "all" to keep all comments- a valid JS regexp (needs to start with aslash) to keep only comments that match.Note that currently not *all* comments can bekept when compression is on, because of deadcode removal or cascading statements intosequences. [string]--preamble Preamble to prepend to the output. You can usethis to insert a comment, for example forlicensing information. This will not beparsed, but the source map will adjust for itspresence.--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. Youneed to pass an argument to this option tospecify the name that your module will takewhen included in, say, a browser. [string]--export-all Only used when --wrap, this tells UglifyJS toadd 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<e.length;o++)e[o].active=t==o?!0:!1;return e};console.log(n("conan")),console.log(n("fens.me")),e.book="o,e.hello=n,e.tab=a}({},function(){return" this}());="" #="" sourcemappingurl="foo.min.js.map" <="" code="">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 <bsspirit@gmail.com>","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規范起來。
轉載請注明出處:
http://blog.fens.me/nodejs-uglifyjs2-js/
轉載于:https://www.cnblogs.com/sunws/p/4783375.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的[转载]用UglifyJS2合并压缩混淆JS代码——javascript系列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 『.NET Core CLI工具文档』(
- 下一篇: JSTL标签库中fmt标签,日期,数字的