综合应用
保留版权告示或其他注释
你可以传入--comments
让输出文件中保留某些注释。默认时会保留JSDoc-style的注释(包含”@preserve”,”@license” 或 “@cc_on”(为IE所编译))。你可以传入--comments all
来保留全部注释,或者传一个合法的正则来保留那些匹配到的注释。例如--comments /^!/
会保留/*! Copyright Notice */
这样的注释。
注意,无论如何,总会有些注释在某些情况下会丢失。例如:
function f() {
/** @preserve Foo Bar */
function g() {
// this function is never called
}
return something();
}
即使里面带有”@preserve”,注释依然会被丢弃。因为内部的函数g
(注释所依附的抽象语法树节点)没有被引用、会被压缩器干掉。
书写版权信息(或其他需要在输出文件中保留的信息)的最安全位置是全局节点。
unsafe``compress
配置
The unsafe
compress
option
在某些刻意营造的案例中,启用某些转换有可能会打断代码的逻辑,但绝大部分情况下是安全的。你可能会想尝试一下,因为这毕竟会减少文件体积。以下是某些例子:
new Array(1, 2, 3)
或Array(1, 2, 3)
→[ 1, 2, 3 ]
new Object()
→{}
String(exp)
或exp.toString()
→"" + exp
new Object/RegExp/Function/Error/Array (...)
→ 我们干掉用new
的void 0
→undefined
(假如作用域中有一个变量名叫”undefined”;我们这幺做是因为变量名会被混淆成单字符)
编译条件语句
Conditional compilation
Uglify会假设全局变量都是常量(不管是否在局部域中定义了),你可以用--define
(-d
)来实现定义全局变量。例如你传--define DEBUG=false
,UglifyJS会在输出中干掉下面代码:
if (DEBUG) {
console.log("debug stuff");
}
你可以像--define env.DEBUG=false
这样写嵌套的常量。
在干掉那些永否的条件语句以及不可达代码时,UglifyJS会给出警告。现在没有选项可以禁用此特性,但你可以设置 warnings=false
来禁掉所有警告。
另一个定义全局常量的方法是,在一个独立的文档中定义,再引入到构建中。例如你有一个这样的build/defines.js
:
const DEBUG = false;
const PRODUCTION = true;
// 等等
这样构建你的代码:
uglifyjs build/defines.js js/foo.js js/bar.js... -c
UglifyJS会注意到这些常量。因为它们无法改变,所以它们会被认为是没被引用而被照样干掉。如果你用const
声明,构建后还会被保留。如果你的运行环境低于ES6、不支持const
,请用var
声明加上reduce_vars
设置(默认启用)来实现。
编译条件语句API
你也可以通过程序API来设置编译配置。其中有差别的是一个压缩器属性global_defs
:
var result = UglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
compress: {
dead_code: true,
global_defs: {
DEBUG: false
}
}
});
在global_defs
配"@"
前缀的表达式,UglifyJS才会替换成语句表达式:
UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"@alert": "console.log"
}
}
}).code;
// returns: 'console.log("hello");'
否则会替换成字符串:
UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"alert": "console.log"
}
}
}).code;
// returns: '"console.log"("hello");'
使用minify()
获得原生UglifyJS ast
Using native Uglify AST with minify()
// 例子: 只解析代码,获得原生Uglify AST
var result = UglifyJS.minify(code, {
parse: {},
compress: false,
mangle: false,
output: {
ast: true,
code: false // optional - faster if false
}
});
// result.ast 即是原生 Uglify AST
// 例子: 输入原生 Uglify AST,接着把它压缩并混淆,生成代码和原生ast
var result = UglifyJS.minify(ast, {
compress: {},
mangle: {},
output: {
ast: true,
code: true // 可选,false更快
}
});
// result.ast 是原生 Uglify AST
// result.code 是字符串格式的最小化后的代码
使用 Uglify AST
Working with Uglify AST
可以通过TreeWalker
和TreeTransformer
分别横截(?transversal)和转换原生AST。
ESTree/SpiderMonkey AST
UglifyJS有自己的抽象语法树格式;为了某些现实的原因
我们无法在内部轻易地改成使用SpiderMonkey AST。但UglifyJS现在有了一个可以输入SpiderMonkeyAST的转换器。
例如Acorn ,这是一个超级快的生成SpiderMonkey AST的解释器。它带有一个实用的迷你CLI,能解释一个文件、把AST转存为JSON并标准输出。可以这样用UglifyJS来压缩混淆:
acorn file.js | uglifyjs --spidermonkey -m -c
-p --spidermonkey
选项能让UglifyJS知道输入文件并非JavaScript,而是SpiderMonkey AST生成的JSON代码。这事我们不用自己的解释器,只把AST转成我们内部AST。
使用 Acorn 来解释代码
Use Acorn for parsing
更有趣的是,我们加了 -p --acorn
选项来使用Acorn解释所有代码。如果你传入这个选项,UglifyJS会require("acorn")
Acorn确实非常快(650k代码原来要380ms,现在只需250ms),但转换Acorn产生的SpiderMonkey树会额外花费150ms。所以总共比UglifyJS自己的解释器还要多花一点时间。
Uglify快速最小化模式
Uglify Fast Minify Mode
很少人知道,对大多数js代码而言,其实移除空格和混淆符号已经占了减少代码体积之中到的95%—不必细致地转换。简单地禁用压缩compress
能加快UglifyJS的构建速度三四倍。我们可以比较一下butternut
和只使用混淆mangle
的模式的Uglify的压缩速度与gzip大小:butternut
:
d3.js | minify size | gzip size | minify time (seconds) |
---|---|---|---|
original | 451,131 | 108,733 | - |
uglify-js@3.0.24 mangle=false, compress=false | 316,600 | 85,245 | 0.70 |
uglify-js@3.0.24 mangle=true, compress=false | 220,216 | 72,730 | 1.13 |
butternut@0.4.6 | 217,568 | 72,738 | 1.41 |
uglify-js@3.0.24 mangle=true, compress=true | 212,511 | 71,560 | 3.36 |
babili@0.1.4 | 210,713 | 72,140 | 12.64 |
在CLI中,这样启用快速最小化模式:
uglifyjs file.js -m
API这样用:
UglifyJS.minify(code, { compress: false, mangle: true });