Created
September 7, 2012 02:50
-
-
Save shenmao1989/3662682 to your computer and use it in GitHub Desktop.
用UglifyJS解析/压缩/格式化你的Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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的优化实现有更好的想法,都可有直接联系作者。 | |
涉及到全局数组构造函数的调用 | |
这时会进行如下转换: | |
new Array(1, 2, 3, 4) => [1,2,3,4] | |
Array(a, b, c) => [a,b,c] | |
new Array(5) => Array(5) | |
new Array(a) => Array(a) | |
在Array没有被重新定义之前,这些转换是安全的。UglifyJS也会对经过用户本地或全局重定义的Array进行处理,但CSSer建议还是不要这么做: | |
// case 1. 全局声明 | |
var Array; | |
new Array(1, 2, www.csser.com); | |
Array(a, b); | |
// 或者后声明 | |
new Array(1, 2, 3); | |
var Array; | |
// 或者定义为函数 | |
new Array(1, 2, 3); | |
function Array() { ... } | |
// case 2. 在函数内部声明 | |
(function(){ | |
a = new Array(1, 2, 3); | |
b = Array(5, 6); | |
var Array; | |
})(); | |
// 或者 | |
(function(Array){ | |
return Array(5, 6, 7); | |
})(); | |
// 或者 | |
(function(){ | |
return new Array(1, 2, 3, 4); | |
function Array() { ... } | |
})(); | |
// 等等. | |
安装 | |
通过NPM安装 | |
UglifyJS已经可以通过NPM进行安装: | |
npm install uglify-js | |
通过GitHub安装最新版本 | |
## 克隆仓库 | |
mkdir -p /where/you/wanna/put/it | |
cd /where/you/wanna/put/it | |
git 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 ~/bin | |
cd ~/bin | |
ln -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); // 解析代码返回初始的AST | |
ast = pro.ast_mangle(ast); // 获取变量名称打乱的AST | |
ast = pro.ast_squeeze(ast); // 获取经过压缩优化的AST | |
var 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压缩相似,在性能上是一流的,所以建议多多实践! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
不错 有很大参考价值 学习了