⽤UglifyJS2合并压缩混淆JS代码
前⾔
做Web前端开发,总是要考虑页⾯的打开速度,如果⽂件数量越少、⽂件长度越⼩,就可以直接的提升⽹页的访问速度。
但在开发的时候,为了保证代码的可读性,我们写的程序⽂件会很多⽽且很⼤,这样就与部署的要求发⽣背离,通过UglifyJS2这个⼯具,我们可以在开发完成时,对代码⽂件进⾏合并、混淆、压缩等的操作,达到最优的访问性能。
⽬录
1. UglifyJS介绍
2. UglifyJS2介绍
3. UglifyJS2安装
4. UglifyJS2命令操作
5. UglifyJS2的API使⽤
1. UglifyJS介绍
开始UglifyJS2介绍之前,我们先要说⼀下UglifyJS。是UglifyJS2的前⾝,是⼀个Javascript开发的通⽤的语法分析、代码压缩、代码优化的⼀个⼯具包。UglifyJS是基于Nodejs 环境开发,⽀持CommonJS模块系统的任意的Javascript平台。
UglifyJS的实现主要分为2部分:
⽣成JS代码的抽象语法树(AST),通过parse-js.js完成。
遍历AST语法树,做各种操作,⽐如⾃动缩进、缩短变量名、删除块括号{}、去空格、常量表达式、连续变量声明、语块合并、去掉⽆法访问的代码等,通过process.js完成。
2. UglifyJS2介绍
是作者对UglifyJS的重写,是完全的重写,⽽不仅仅是升级。从UglifyJS2官司⽅⽹页介绍看,UglifyJS2把整个的JS压缩过程,做了更进⼀步的细化。
,⽤于实现抽象语⾔法树(AST)。
, 通过AST⽣成JS代码和source map。
, ⽤于JS代码的压缩。
, ⽤于减少局部变量的命名,⽤单字母替换。
, ⽤来判断变量定义范围和变量引⽤范围的⼯具。
, AST树遍历⼯具。
, AST树转换⼯具。
上述所有的功能代码API是在6500⾏的左右,⽐其他的相同功能的开发包都要⼩。作者还提供了⼀个在线版本UglifyJS2的JS压缩⼯具,,⼤家可以测试⼀下。
3. UglifyJS2安装
系统环境:
win7 64bit
Nodejs:v0.10.5
Npm:1.2.19
UglifyJS2的安装⾮常简单,和Nodejs的其他包⼀样,全局安装使⽤如下命令。
[plain]
1. npm install uglify-js -g
也可以通过github下载源代码安装。
[plain]
jquery源码在线1. git clone git://github/mishoo/UglifyJS
2.git
2. cd UglifyJS2
我们在使⽤UglifyJS2的时候主要有2种⽅式,⼀种是通过命令⾏操作,对指定的JS⽂件进⾏压缩;另⼀种是通过程序的API调⽤,对⽂件或内存中的JS代码进⾏压缩。下⾯我将分两种情况进⾏介绍。
4. UglifyJS2命令操作
在全局安装好UglifyJS2以后,我们就可以使⽤UglifyJS2的命令了。
打印uglifyjs命令⾏的帮助信息,会打出很长⼀段说明。
[plain]
1. D:\workspace\javascript\nodejs-uglifyJS2>uglifyjs -h
2. D:\toolkit\nodejs\\ D:\toolkit\nodejs\node_modules\uglify-js\bin\uglifyjs input1.js [input2.js ...] [options]
3. Use a single dash to read input from the standard input.
4.
5. NOTE: by default there is no mangling/compression.
6. Without [options] it will simply parse input files and dump the AST
7. with whitespace and comments discarded.  To achieve compression and
8. mangling you need to use `-c` and `-m`.
9.
10. Options:
11.  --source-map                  Specify an output file where to generate source
12.                                map.                                    [string]
13.  --source-map-root            The path to the original source to be included
14.                                in the source map.                      [string]
15.  --source-map-url              The path to the source map to be added in //#
16.                                sourceMappingURL.  Defaults to the value passed
17.                                with --source-map.                      [string]
18.  --source-map-include-sources  Pass this flag if you want to include the
19.                                content of source files in the source map as
20.                                sourcesContent property.              [boolean]
21.  --in-source-map              Input source map, useful if you're compressing
22.                                JS that was generated from some other original
23.                                code.
24.  --screw-ie8                  Pass this flag if you don't care about full
25.                                compliance with Internet Explorer 6-8 quirks
26.                                (by default UglifyJS will try to be IE-proof).
27.                                                                        [boolean]
28.  --expr                        Parse a single expression, rather than a
29.                                program (for parsing JSON)            [boolean]
30.  -p, --prefix                  Skip prefix for original filenames that appear
31.                                in source maps. For example -p 3 will drop 3
32.                                directories from file names and ensure they are
33.                                relative paths. You can also specify -p
34.                                relative, which will make UglifyJS figure out
35.                                itself the relative paths between original
36.                                sources, the source map and the output file.
37.                                                                        [string]
38.  -o, --output                  Output file (default STDOUT).
39.  -b, --beautify                Beautify output/specify output options.
40.                                                                        [string]
41.  -m, --mangle                  Mangle names/pass mangler options.      [string]
42.  -r, --reserved                Reserved names to exclude from mangling.
43.  -c, --compress                Enable compressor/pass compressor options. Pass
44.                                options like -c
45.                                hoist_vars=false,if_return=false. Use -c with
46.                                no argument to use the default compression
47.                                options.                                [string]
48.  -d, --define                  Global definitions                      [string]
49.  -e, --enclose                Embed everything in a big function, with a
50.                                configurable parameter/argument list.  [string]
51.  --comments                    Preserve copyright comments in the output. By
52.                                default this works like Google Closure, keeping
53.                                JSDoc-style comments that contain "@license" or
54.                                "@preserve". You can optionally pass one of the
55.                                following arguments to this flag:
56.                                - "all" to keep all comments
57.                                - a valid JS regexp (needs to start with a
58.                                slash) to keep only comments that match.
59.                                Note that currently not *all* comments can be
60.                                kept when compression is on, because of dead
61.                                code removal or cascading statements into
62.                                sequences.                              [string]
63.  --preamble                    Preamble to prepend to the output.  You can use
64.                                this to insert a comment, for example for
65.                                licensing information.  This will not be
66.                                parsed, but the source map will adjust for its
67.                                presence.
68.  --stats                      Display operations run time on STDERR.
69.                                                                        [boolean]
70.  --acorn                      Use Acorn for parsing.                [boolean]
71.  --spidermonkey                Assume input files are SpiderMonkey AST format
72.                                (as JSON).                            [boolean]
73.  --self                        Build itself (UglifyJS2) as a library (implies
74.                                --wrap=UglifyJS --export-all)          [boolean]
75.  --wrap                        Embed everything in a big function, making the
76.                                “exports” and “global” variables available. You
77.                                need to pass an argument to this option to
78.                                specify the name that your module will take
79.                                when included in, say, a browser.      [string]
80.  --export-all                  Only used when --wrap, this tells UglifyJS to
81.                                add code to automatically export all globals.
82.                                                                        [boolean]
83.  --lint                        Display some scope warnings            [boolean]
84.  -v, --verbose                Verbose                                [boolean]
85.  -V, --version                Print version number and exit.        [boolean]
86.  --noerr                      Don't throw an error for unknown options in -c,
87.                                -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。
[plain]
1. ~ vi D:\workspace\javascript\nodejs-uglifyJS2\demo.js
2.
3. 'use strict';
4.
5. function hello(name){
6.    if(name===''){
7.        return "Long time no see, "+name;
8.    }
9.    return "hello "+name;
10. }
11.
12. console.log(hello('Conan'));
13. console.log(hello(''));
main.js
[plain]
1. ~ vi D:\workspace\javascript\nodejs-uglifyJS2\main.js
2.
3. 'use strict';
4.
5. function book(){
6.    return [
7.        {head:'前⾔',page:'/views/tpl/book-r1/preface.html',active:false},
8.        {head:'⽬录',page:'/views/tpl/book-r1/contents.html',active:true},
9.        {head:'代码',page:'/views/tpl/book-r1/code.html',active:false},
10.        {head:'试读',page:'/views/tpl/book-r1/sample.html',active:false},
11.        {head:'勘误',page:'/views/tpl/book-r1/mistake.html',active:false}
12.    ];
13. }
14.
15. var tab=function(arr,idx){
16.    for(var i=0;i<arr.length;i++){
17.        arr[i].active = (idx==i?true:false);
18.    }
19.    return arr;
20. }
21.
22. console.log(tab(book(),3));
接下来,⽤UglifyJS2命令进⾏操作,合并两个⽂件,对变量名⽤单字母替换,进⾏压缩,所有代码合并到⼀个函数,⽣成source map,指定source map来源⽹站。
[plain]
1. D:\workspace\javascript\nodejs-uglifyJS2>uglifyjs main.js demo.js -o foo.min.js --source-map foo.min.js.map --source-map-root -p 5 -c -m --wrap --export-
all
在当前⽬录⽣成了2个新⽂件:foo.min.js.map, foo.min.js,分别查看这两个⽂件。
foo.min.js
[plain]
1. !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){"===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
[plain]
1. {"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
通过⼀条简单的命令,就实现了对JS代码的合并、压缩等的操作,确实⾮常⽅便。
下载jquery-2.1.1.js⽂件⾃⼰压缩,并与官⽅的压缩⽂件进⾏对⽐。
[plain]
1. # 下载
2. ~ wget code.jquery/jquery-2.1.1.js
3. ~ wget code.jquery/jquery-2.1.1.min.js
4.
5. # 压缩
6. ~ uglifyjs jquery-2.1.1.js -o jquery-2.1.1.min.uglifyjs2.js -p 5 -c -m
7.
8. # ⽐较3个⽂件⼤⼩
9. ~ ls -l
10. -rwx------  1 4294967295 mkpasswd 247351 Jul  6 16:26 jquery-2.1.1.js
11. -rwx------  1 4294967295 mkpasswd  84245 Jul  6 16:32 jquery-2.1.1.min.js
12. -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
[plain]
1. ~ vi D:\workspace\javascript\nodejs-uglifyJS2\package.json
2.
3.
4. {
5.  "name": "nodejs-uglifyjs2",
6.  "version": "0.0.1",
7.  "description": "uglifyjs2",
8.  "author": "Conan Zhang ",
9.  "dependencies": {
10.  }
11. }
下载UglifyJS2依赖包
[plain]
1. D:\workspace\javascript\nodejs-uglifyJS2>npm install uglify-js --save
2. npm WARN package.json nodejs-uglifyjs2@0.0.1 No readme data!
3. npm http GET /uglify-js
4. npm http 304 /uglify-js
5. npm http GET /async
6. npm http GET /source-map
7. npm http GET /optimist
8. npm http GET /uglify-to-browserify
9. npm http 304 /uglify-to-browserify
10. npm http 304 /optimist
11. npm http 304 /async
12. npm http 304 /source-map
13. npm http GET /wordwrap
14. npm http GET /amdefine
15. npm http 304 /wordwrap
16. npm http 304 /amdefine
17. uglify-js@2.4.14 node_modules\uglify-js
18. ├── uglify-to-browserify@1.0.2
19. ├── async@0.2.10
20. ├── optimist@0.3.7 (wordwrap@0.0.2)
21. └── source-map@0.1.34 (amdefine@0.1.0)
我们新建⼀个⽂件uglify2.js,⽤于编写程序。
[plain]
1. ~ vi D:\workspace\javascript\nodejs-uglifyJS2\uglify
2.js
2.
3. 'use strict';
4.
5. var UglifyJS = require('uglify-js');
6.
7. //代码压缩
8. var result = UglifyJS.minify("var b = function () {};", {fromString: true});
9. console.log("\n===========================");
10. console.log(result);
11.
12. //⽂件压缩
13. result = UglifyJS.minify(["demo.js"]);
14. console.log("\n===========================");
15. console.de);
16.
17. //多⽂件压缩,指定source map和⽹站来源
18. result = UglifyJS.minify(["main.js","demo.js"],{
19.    outSourceMap: "out.js.map",
20.    sourceRoot: "",
21.    mangle:true
22. });
23. console.log("\n===========================");
24. console.de);
25. console.log(result.map);
程序输出:
[plain]
1. D:\workspace\javascript\nodejs-uglifyJS2>node uglify
2.js
2.
3. ===========================
4. { code: 'var b=function(){};', map: 'null' }
5.
6. ===========================
7. "use strict";function hello(e){"===e?"Long time no see, "+e:"hello "+e}var tab=function(e,o){for(var n=0;n
8. <e.length;n++)e[n].active=o==n?!0:!1;return e};console.log(hello("Conan")),console.log(hello(""));
9.
10. ===========================
11. "use strict";function book(){return[{head:"前⾔",page:"/views/tpl/book-r1/preface.html",active:!1},{head:"⽬录",page:"/v
12. iews/tpl/book-r1/contents.html",active:!0},{head:"代码",page:"/views/tpl/book-r1/code.html",active:!1},{head:"试读",page
13. :"/views/tpl/book-r1/sample.html",active:!1},{head:"勘误",page:"/views/tpl/book-r1/mistake.html",active:!1}]}function he
14. llo(e){"===e?"Long time no see, "+e:"hello "+e}console.log(tab(book(),3));var tab=function(e,o){for(var t=
15. 0;t<e.length;t++)e[t].active=o==t?!0:!1;return e};console.log(hello("Conan")),console.log(hello(""));
16. //# sourceMappingURL=out.js.map
17. {"version":3,"file":"out.js.map","sources":["main.js","demo.js"],"names":["book","head","page","active","hello","name","
18. console","log","tab","arr","idx","i","length"],"mappings":"AAAA,YAEA,SAASA,QACL,QACKC,KAAK,KAAKC,KAAK,kCAAkCC,QAAO,IACxD
19. F,KAAK,KAAKC,KAAK,mCAAmCC,QAAO,IACzDF,KAAK,KAAKC,KAAK,+BAA+BC,QAAO,IACrDF,KAAK,KAAKC,KAAK,iCAAiCC,QAAO,IACvDF,KAAK,KAAKC
20. ,KAAK,kCAAkCC,QAAO,ICNjE,QAASC,OAAMC,GACd,MAAU,YAAPA,EACK,qBAAqBA,EAEtB,SAASA,EDMjBC,QAAQC,IAAIC,IAAIR,OAAO,GCDvB,IAAIQ,
21. KAAI,SAASC,EAAIC,GACpB,IAAI,GAAIC,GAAE,EAAEA,EAAEF,EAAIG,OAAOD,IACxBF,EAAIE,GAAGR,OAAUO,GAAKC,GAAE,GAAK,CAE9B,OAAOF,GAGR
22. H,SAAQC,IAAIH,MAAM,UAClBE,QAAQC,IAAIH,MAAM","sourceRoot":""}
我们看到⽤操作uglifyJS2包的API,还是挺简单的,如果对AST树有遍历需求,API提供了⾮常实⽤的函数⽀持。
不过我在测试API过程中,发现有2个问题。
通过API设置mangle选项,但输出没有效果。
没有--wrap和--export-all 命令⾏参数对应的API。
通过本⽂的介绍,我们基本上了解了uglifyJS2包的功能和使⽤⽅法,然后就可以放⼼⼤胆地对JS代码进⾏压缩了。在实际的前端项⽬中,⼀般不⽤⾃⼰配置uglifyJS2包,⽽是通过grunt来调⽤uglifyJS2进⾏代码发布前的压缩,关于grunt使⽤,请参考⽂章:。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。