本文檔譯自UglifyJS3文檔。
此前翻譯的UglifyJS2中文文檔已挪到本項(xiàng)目UglifyJS2分支。
由于webpack本身集成了UglifyJS插件(webpack.optimize.UglifyJsPlugin),其命令webpack -p
即表示調(diào)用UglifyJS來(lái)壓縮代碼,還有不少webpack插件如html-webpack-plugin
也會(huì)默認(rèn)使用UglifyJS。因此我們其實(shí)經(jīng)常要用到它,但UglifyJS本身配置較復(fù)雜/選項(xiàng)繁多,又沒(méi)有中文文檔,使用起來(lái)如墜云霧。鑒于此特翻譯此文,謬誤甚多,敬請(qǐng)斧正。
詞典:
parse 解釋 compress 壓縮 mangle 混淆 beautify 美化 minify 最小化 CLI 命令行工具 sourcemap 編譯后代碼對(duì)源碼的映射,用于網(wǎng)頁(yè)調(diào)試 AST 抽象語(yǔ)法樹(shù) name 名字,包括變量名、函數(shù)名、屬性名 toplevel 頂層作用域 unreachable 不可達(dá)代碼 option 選項(xiàng)/配置 STDIN 標(biāo)準(zhǔn)輸入,指在命令行中直接輸入 STDOUT 標(biāo)準(zhǔn)
以下為正文:
UglifyJS 是一個(gè)js 解釋器、最小化器、壓縮器、美化器工具集(parser, minifier, compressor or beautifier toolkit)。
注意:
uglify-js@3
的API 和 CLI已簡(jiǎn)化,不再向后兼容 uglify-js@2
.
UglifyJS 2.x
文檔在這里.
uglify-js
只支持 ECMAScript 5 (ES5).
假如希望壓縮 ES2015+ (ES6+)代碼,應(yīng)該使用 uglify-es這個(gè)npm
包。
首先確認(rèn)一直你已經(jīng)安裝了最新的node.js(裝完后或許需要重啟一下電腦)
用NPM安裝CLI:
npm install uglify-js -g
用NPM下載給程序使用:
npm install uglify-js
uglifyjs [input files] [options]
UglifyJS可以輸入多文件。建議你先寫輸入文件,再傳選項(xiàng)。UglifyJS會(huì)根據(jù)壓縮選項(xiàng),把文件放在隊(duì)列中依次解釋。所有文件都會(huì)在同一個(gè)全局域中,假如一個(gè)文件中的變量、方法被另一文件引用,UglifyJS會(huì)合理地匹配。
假如沒(méi)有指定文件,UglifyJS會(huì)讀取輸入字符串(STDIN)。
如果你想要把選項(xiàng)寫在文件名的前面,那要在二者之前加上雙橫線,防止文件名被當(dāng)成了選項(xiàng):
uglifyjs --compress --mangle -- input.js
-h, --help 列出使用指南。 `--help options` 獲取可用選項(xiàng)的詳情。 -V, --version 打印版本號(hào)。 -p, --parse <options> 指定解析器配置選項(xiàng): `acorn` 使用 Acorn 來(lái)解析。 `bare_returns` 允許在函數(shù)外return。 在壓縮CommonJS模塊或`.user.js `引擎調(diào)用被同步執(zhí)行函數(shù)包裹的用戶腳本 時(shí)會(huì)用到。 `expression` 不是解析文件,二是解析一段表達(dá)式 (例如解析JSON). `spidermonkey` 輸入文件是 SpiderMonkey AST 格式 (JSON). -c, --compress [options] 啟用壓縮(true/false)/指定壓縮配置: `pure_funcs` 傳一個(gè)函數(shù)名的列表,當(dāng)這些函數(shù)返回值沒(méi)被利用時(shí),該函數(shù)會(huì)被安全移除。 -m, --mangle [options] 啟用混淆(true/false)/指定混淆配置: `reserved` 不被混淆的名字列表。 --mangle-props [options] 混淆屬性/指定壓縮配置: `builtins` 混淆那些與標(biāo)準(zhǔn)JS全局變量重復(fù)的名字。 `debug` 添加debug前綴和后綴。 `domprops` 混淆那些魚DOM屬性名重復(fù)的名字。 `keep_quoted` 只混淆沒(méi)括起來(lái)的屬性名。 `regex` 只混淆匹配(該正則)的名字。 `reserved` 不需要混淆的名字的列表(即保留)。 -b, --beautify [options] 是否美化
指定--output
(-o
)來(lái)明確輸出文件,否則將在終端輸出(STDOUT)
UglifyJS可以生成一份sourcemap文件,這非常有利于你調(diào)試壓縮后的JS代碼。傳--source-map --output output.js
來(lái)獲取sorcemap文件(sorcemap會(huì)生成為output.js.map
)。
額外選項(xiàng):
--source-map filename=<NAME>
指定sourcemap名字。
--source-map root=<URL>
傳一個(gè)源文件的路徑。否則UglifyJS將假定已經(jīng)用了HTTPX-SourceMap
,并將省略//#sourceMappingURL=
指示。
--source-map url=<URL>
指定生成sourcemap的路徑。
例如:
uglifyjs js/file1.js js/file2.js \ -o foo.min.js -c -m \ --source-map root="http://foo.com/src",url=foo.min.js.map
上述配置會(huì)壓縮和混淆file1.js
、file2.js
,輸出文件foo.min.js
和sourcemapfoo.min.js.map
,sourcemap會(huì)建立http://foo.com/src/js/file1.js
、 http://foo.com/src/js/file2.js
的映射。(實(shí)際上,sourcemap根目錄是http://foo.com/src
,所以相當(dāng)于源文件路徑是js/file1.js
、js/file2.js
)
假如你的JS代碼是用其他編譯器(例如coffeescript)生成的,那么映射到JS代碼就沒(méi)什么用了,你肯定希望映射到CoffeeScript源碼。UglifyJS有一個(gè)選項(xiàng)可以輸入sourcemap,假如你有一個(gè)從CoffeeScript → 編譯后JS的map的話,UglifyJS可以生成一個(gè)從CoffeeScript->壓縮后JS的map映射到源碼位置。
你可以傳入 --source-map content="/path/to/input/source.map"
或來(lái)嘗試此特性,如果sourcemap包含在js內(nèi),則寫 --source-map content=inline
。
你需要傳入--mangle
(-m
)來(lái)使啟用混淆功能。支持以下選項(xiàng)(用逗號(hào)隔開(kāi)):
toplevel
— 混淆在最高作用域中聲明的變量名(默認(rèn)disabled)
eval
- 混淆在eval
或 with
作用域出現(xiàn)的變量名(默認(rèn)disabled)當(dāng)啟用混淆功能時(shí),如果你希望保留一些名字不被混淆,你可以用--mangle reserved
聲明一些名字(用逗號(hào)隔開(kāi))。例如:
uglifyjs ... -m reserved=[$,require,exports]'
這樣能防止require
, exports
和 $
被混淆改變。
--mangle-props
)--mangle-props
)**警告:**這能會(huì)搞崩你的代碼?;煜龑傩悦煜兞棵灰粯?,是相互的。傳入--mangle-props
會(huì)混淆對(duì)象所有可見(jiàn)的屬性名,除了DOM屬性名和JS內(nèi)置的類名。例如:
// example.js var x = { baz_: 0, foo_: 1, calc: function() { return this.foo_ + this.baz_; } }; x.bar_ = 2; x["baz_"] = 3; console.log(x.calc());
混淆所有屬性(除了JS內(nèi)置的):
$ uglifyjs example.js -c -m --mangle-props
var x={o:0,_:1,l:function(){return this._+this.o}};x.t=2,x.o=3,console.log(x.l());
混淆除了 reserved
(保留)外的所有屬性:
$ uglifyjs example.js -c -m --mangle-props reserved=[foo_,bar_]
var x={o:0,foo_:1,_:function(){return this.foo_+this.o}};x.bar_=2,x.o=3,console.log(x._());
混淆匹配regex
(正則)的屬性:
$ uglifyjs example.js -c -m --mangle-props regex=/_$/
var x={o:0,_:1,calc:function(){return this._+this.o}};x.l=2,x.o=3,console.log(x.calc());
混用多個(gè)混淆屬性選項(xiàng):
$ uglifyjs example.js -c -m --mangle-props regex=/_$/,reserved=[bar_]
var x={o:0,_:1,calc:function(){return this._+this.o}};x.bar_=2,x.o=3,console.log(x.calc());
為了混淆正常使用,我們默認(rèn)避免混淆標(biāo)準(zhǔn)JS內(nèi)置的名字(--mangle-props builtins
可以強(qiáng)制混淆)。
tools/domprops.json
里有一個(gè)默認(rèn)的排除名單,包括絕大部分標(biāo)準(zhǔn)JS和多種瀏覽器中的DOM屬性名。傳入--mangle-props domprops
可以讓此名單失效。
可以用正則表達(dá)式來(lái)定義該混淆的屬性名。例如--mangle-props regex=/^_/
,只混淆下劃線開(kāi)頭的屬性。
當(dāng)你壓縮多個(gè)文件時(shí),為了保證讓它們最終能同時(shí)工作,我們要讓他們中同樣的屬性名混淆成相同的結(jié)果。傳入--name-cache filename.json
,UglifyJS會(huì)維護(hù)一個(gè)共同的映射供他們復(fù)用。這個(gè)json一開(kāi)始應(yīng)該是空的,例如:
$ rm -f /tmp/cache.json # start fresh $ uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js $ uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
這樣part1.js
和 part2.js
會(huì)知曉對(duì)方混淆的屬性名。
假如你把所有文件壓縮成同一個(gè)文件,那就不需要啟用名字緩存了。
混淆沒(méi)括起來(lái)的名字(--mangle-props keep_quoted
)
--mangle-props keep_quoted
)使用括號(hào)屬性名 (o["foo"]
)以保留屬性名(foo
)。這會(huì)讓整個(gè)腳本中其余此屬性的引用(o.foo
)也不被混淆。例如:
// stuff.js var o = { "foo": 1, bar: 3 }; o.foo += o.bar; console.log(o.foo);
$ uglifyjs stuff.js --mangle-props keep_quoted -c -m
var o={foo:1,o:3};o.foo+=o.o,console.log(o.foo);
調(diào)試屬性名混淆
為了混淆屬性時(shí)不至于完全分不清,你可以傳入--mangle-props debug
來(lái)調(diào)試。例如o.foo
會(huì)被混淆成o._$foo$_
。這讓源碼量大、屬性被混淆時(shí)也可以debug,可以看清混淆會(huì)把哪些屬性搞亂。
$ uglifyjs stuff.js --mangle-props debug -c -m
var o={_$foo$_:1,_$bar$_:3};o._$foo$_+=o._$bar$_,console.log(o._$foo$_);
你可以用--mangle-props-debug=XYZ
來(lái)傳入自定義后綴。讓o.foo
混淆成 o._$foo$XYZ_
, 你可以在每次編譯是都改變一下,來(lái)辨清屬性名怎么被混淆的。一個(gè)小技巧,你可以每次編譯時(shí)傳隨機(jī)數(shù)來(lái)模仿混淆操作(例如你更新了腳本,有了新的屬性名),這有助于識(shí)別混淆時(shí)的出錯(cuò)。
假如是通過(guò)NPM安裝的,你可以在你的應(yīng)用中這樣加載UglifyJS:
var UglifyJS = require("uglify-js");
這輸出一個(gè)高級(jí)函數(shù)**minify(code, options)
**,它能根據(jù)配置,實(shí)現(xiàn)多種最小化(即壓縮、混淆等)。 minify()
默認(rèn)啟用壓縮和混淆選項(xiàng)。例子:
var code = "function add(first, second) { return first + second; }"; var result = UglifyJS.minify(code); console.log(result.error); // runtime error, or `undefined` if no error console.log(result.code); // minified output: function add(n,d){return n+d}
你可以通過(guò)一個(gè)對(duì)象(key為文件名,value為代碼)來(lái)同時(shí)最小化
多個(gè)文件:
var code = { "file1.js": "function add(first, second) { return first + second; }", "file2.js": "console.log(add(1 + 2, 3 + 4));" }; var result = UglifyJS.minify(code); console.log(result.code); // function add(d,n){return d+n}console.log(add(3,7));
toplevel
選項(xiàng)例子:
var code = { "file1.js": "function add(first, second) { return first + second; }", "file2.js": "console.log(add(1 + 2, 3 + 4));" }; var options = { toplevel: true }; var result = UglifyJS.minify(code, options); console.log(result.code); // console.log(3+7);
nameCache
選項(xiàng)例子:
var options = { mangle: { toplevel: true, }, nameCache: {} }; var result1 = UglifyJS.minify({ "file1.js": "function add(first, second) { return first + second; }" }, options); var result2 = UglifyJS.minify({ "file2.js": "console.log(add(1 + 2, 3 + 4));" }, options); console.log(result1.code); // function n(n,r){return n+r} console.log(result2.code); // console.log(n(3,7));
你可以像下面這樣把名字緩存保存在文件中:
var cacheFileName = "/tmp/cache.json"; var options = { mangle: { properties: true, }, nameCache: JSON.parse(fs.readFileSync(cacheFileName, "utf8")) }; fs.writeFileSync("part1.js", UglifyJS.minify({ "file1.js": fs.readFileSync("file1.js", "utf8"), "file2.js": fs.readFileSync("file2.js", "utf8") }, options).code, "utf8"); fs.writeFileSync("part2.js", UglifyJS.minify({ "file3.js": fs.readFileSync("file3.js", "utf8"), "file4.js": fs.readFileSync("file4.js", "utf8") }, options).code, "utf8"); fs.writeFileSync(cacheFileName, JSON.stringify(options.nameCache), "utf8");
綜合使用多種minify()
選項(xiàng)的例子:
var code = { "file1.js": "function add(first, second) { return first + second; }", "file2.js": "console.log(add(1 + 2, 3 + 4));" }; var options = { toplevel: true, compress: { global_defs: { "@console.log": "alert" }, passes: 2 }, output: { beautify: false, preamble: "/* uglified */" } }; var result = UglifyJS.minify(code, options); console.log(result.code); // /* uglified */ // alert(10);"
生成警告提示:
var code = "function f(){ var u; return 2 + 3; }"; var options = { warnings: true }; var result = UglifyJS.minify(code, options); console.log(result.error); // runtime error, `undefined` in this case console.log(result.warnings); // [ 'Dropping unused variable u [0:1,18]' ] console.log(result.code); // function f(){return 5}
生成錯(cuò)誤提示:
var result = UglifyJS.minify({"foo.js" : "if (0) else console.log(1);"}); console.log(JSON.stringify(result.error)); // {"message":"Unexpected token: keyword (else)","filename":"foo.js","line":1,"col":7,"pos":7}
Note: unlike uglify-js@2.x
, the 3.x
API does not throw errors. To achieve a similar effect one could do the following:
var result = UglifyJS.minify(code, options); if (result.error) throw result.error;
warnings
(default false
) — 傳 true
的話,會(huì)在result.warnings
中返回壓縮過(guò)程的警告。傳 "verbose"
獲得更詳細(xì)的警告。
parse
(default {}
) — 如果你要指定額外的解析配置parse options,傳配置對(duì)象。compress
(default {}
) — 傳false
就完全跳過(guò)壓縮。傳一個(gè)對(duì)象來(lái)自定義 壓縮配置compress options。mangle
(default true
) — 傳 false
就跳過(guò)混淆名字。傳對(duì)象來(lái)指定混淆配置mangle options (詳情如下).mangle.properties
(default false
) — 傳一個(gè)對(duì)象來(lái)自定義混淆屬性配置mangle property options.
output
(default null
) — 要自定義就傳個(gè)對(duì)象來(lái)指定額外的 輸出配置output options. 默認(rèn)是壓縮到最優(yōu)化。sourceMap
(default false
) - 傳一個(gè)對(duì)象來(lái)自定義 sourcemap配置source map options.toplevel
(default false
) - 如果你要混淆(和干掉沒(méi)引用的)最高作用域中的變量和函數(shù)名,就傳true
。nameCache
(default null
) - 如果你要緩存 minify()
多處調(diào)用的經(jīng)混淆的變量名、屬性名,就傳一個(gè)空對(duì)象{}
或先前用過(guò)的nameCache
對(duì)象。 注意:這是個(gè)可讀/可寫屬性。minify()
會(huì)讀取這個(gè)對(duì)象的nameCache狀態(tài),并在最小化過(guò)程中更新,以便保留和供用戶在外部使用。ie8
(default false
) - 傳 true
來(lái)支持 IE8.{ warnings: false, parse: { // parse options }, compress: { // compress options }, mangle: { // mangle options properties: { // mangle property options } }, output: { // output options }, sourceMap: { // source map options }, nameCache: null, // or specify a name cache object toplevel: false, ie8: false, }
這樣生成sourcemap:
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, { sourceMap: { filename: "out.js", url: "out.js.map" } }); console.log(result.code); // minified output console.log(result.map); // source map
要注意,此時(shí)sourcemap并不會(huì)保存為一份文件,它只會(huì)返回在result.map
中。 sourceMap.url
傳入的值只用來(lái)在result.code
中設(shè)置//# sourceMappingURL=out.js.map
,filename
的值只用來(lái)在sourcemap文件中設(shè)置 file
屬性(詳情看 規(guī)范)。
你可以把sourceMap.url
設(shè)為true
,這樣sourcemap會(huì)加在代碼末尾。
你也可以指定sourcemap中的源文件根目錄(sourceRoot)屬性:
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, { sourceMap: { root: "http://example.com/src", url: "out.js.map" } });
如果你要壓縮從其他文件編譯得來(lái)的帶一份sourcemap的JS文件,你可以用sourceMap.content
參數(shù):
var result = UglifyJS.minify({"compiled.js": "compiled code"}, { sourceMap: { content: "content from compiled.js.map", url: "minified.js.map" } }); // same as before, it returns `code` and `map`
如果你要用X-SourceMap
請(qǐng)求頭,你可以忽略 sourceMap.url
。
bare_returns
(default false
) -- 支持在頂級(jí)作用域中 return
聲明。
html5_comments
(default true
)
shebang
(default true
) -- 支持在第一行用 #!command
sequences
(default: true) -- 連續(xù)聲明變量,用逗號(hào)隔開(kāi)來(lái)??梢栽O(shè)置為正整數(shù)來(lái)指定連續(xù)聲明的最大長(zhǎng)度。如果設(shè)為true
表示默認(rèn)200
個(gè),設(shè)為false
或0
則禁用。 sequences
至少要是2
,1
的話等同于true
(即200
)。默認(rèn)的sequences設(shè)置有極小幾率會(huì)導(dǎo)致壓縮很慢,所以推薦設(shè)置成20
或以下。
properties
-- 用.
來(lái)重寫屬性引用,例如foo["bar"] → foo.bar
dead_code
-- 移除沒(méi)被引用的代碼drop_debugger
-- 移除 debugger;
unsafe
(default: false) -- 使用 "unsafe"轉(zhuǎn)換 (下面詳述)unsafe_comps
(default: false) -- 保留<
和 <=
不被換成 >
和 >=
。假如某些運(yùn)算對(duì)象是用get
或 valueOf
object得出的時(shí)候,轉(zhuǎn)換可能會(huì)不安全,可能會(huì)引起運(yùn)算對(duì)象的改變。此選項(xiàng)只有當(dāng) comparisons
和unsafe_comps
都設(shè)為true時(shí)才會(huì)啟用。unsafe_Func
(default: false) -- 當(dāng) Function(args, code)
的args
和 code
都是字符串時(shí),壓縮并混淆。unsafe_math
(default: false) -- 優(yōu)化數(shù)字表達(dá)式,例如2 * x * 3
變成 6 * x
, 可能會(huì)導(dǎo)致不精確的浮點(diǎn)數(shù)結(jié)果。unsafe_proto
(default: false) -- 把Array.prototype.slice.call(a)
優(yōu)化成 [].slice.call(a)
unsafe_regexp
(default: false) -- 如果RegExp
的值是常量,替換成變量。conditionals
-- 優(yōu)化if
等判斷以及條件選擇comparisons
-- 把結(jié)果必然的運(yùn)算優(yōu)化成二元運(yùn)算,例如!(a <= b) → a > b
(只有設(shè)置了 unsafe_comps
時(shí)才生效);盡量轉(zhuǎn)成否運(yùn)算。例如 a = !b && !c && !d && !e → a=!(b||c||d||e)
evaluate
-- 嘗試計(jì)算常量表達(dá)式booleans
-- 優(yōu)化布爾運(yùn)算,例如 !!a? b : c → a ? b : c
typeofs
-- 默認(rèn) true
. 轉(zhuǎn)換 typeof foo == "undefined"
成 foo === void 0
. 注意:如果要適配IE10或以下,由于已知的問(wèn)題,推薦設(shè)成false
。loops
-- 當(dāng)do
、while
、 for
循環(huán)的判斷條件可以確定是,對(duì)其進(jìn)行優(yōu)化。unused
-- 干掉沒(méi)有被引用的函數(shù)和變量。(除非設(shè)置"keep_assign"
,否則變量的簡(jiǎn)單直接賦值也不算被引用。)toplevel
-- 干掉頂層作用域中沒(méi)有被引用的函數(shù) ("funcs"
)和/或變量("vars"
) (默認(rèn)是false
, true
的話即函數(shù)變量都干掉)top_retain
-- 當(dāng)設(shè)了unused
時(shí),保留頂層作用域中的某些函數(shù)變量。(可以寫成數(shù)組,用逗號(hào)隔開(kāi),也可以用正則或函數(shù). 參考toplevel
)hoist_funs
-- 提升函數(shù)聲明hoist_vars
(default: false) -- 提升 var
聲明 (默認(rèn)是false
,因?yàn)槟菚?huì)加大文件的size)if_return
-- 優(yōu)化 if/return 和 if/continueinline
-- 包裹簡(jiǎn)單函數(shù)。join_vars
-- 合并連續(xù) var
聲明cascade
-- 弱弱地優(yōu)化一下連續(xù)聲明, 將 x, x
轉(zhuǎn)成 x
,x = something(), x
轉(zhuǎn)成 x = something()
collapse_vars
-- 當(dāng) var
和 const
單獨(dú)使用時(shí)盡量合并reduce_vars
-- 優(yōu)化某些變量實(shí)際上是按常量值來(lái)賦值、使用的情況。warnings
-- 當(dāng)刪除沒(méi)有用處的代碼時(shí),顯示警告negate_iife
-- 當(dāng)立即執(zhí)行函數(shù)(IIFE)的返回值沒(méi)用時(shí),取消之。避免代碼生成器會(huì)插入括號(hào)。pure_getters
-- 默認(rèn)是 false
. 如果你傳入true
,UglifyJS會(huì)假設(shè)對(duì)象屬性的引用(例如foo.bar
或 foo["bar"]
)沒(méi)有函數(shù)副作用。pure_funcs
-- 默認(rèn) null
. 你可以傳入一個(gè)名字的數(shù)組,UglifyJS會(huì)假設(shè)這些函數(shù)沒(méi)有函數(shù)副作用。**警告:**假如名字在作用域中重新定義,不會(huì)再次檢測(cè)。例如var q = Math.floor(a/b)
,假如變量q
沒(méi)有被引用,UglifyJS會(huì)干掉它,但 Math.floor(a/b)
會(huì)被保留,沒(méi)有人知道它是干嘛的。你可以設(shè)置pure_funcs: [ 'Math.floor' ]
,這樣該函數(shù)會(huì)被認(rèn)為沒(méi)有函數(shù)副作用,這樣整個(gè)聲明會(huì)被廢棄。在目前的執(zhí)行情況下,會(huì)增加開(kāi)銷(壓縮會(huì)變慢)。drop_console
-- 默認(rèn) false
. 傳true
的話會(huì)干掉console.*
函數(shù)。如果你要干掉特定的函數(shù)比如console.info
,又想刪掉后保留其參數(shù)中的副作用,那用pure_funcs
來(lái)處理吧。expression
-- 默認(rèn) false
。傳true
來(lái)保留終端語(yǔ)句中沒(méi)有"return"的完成值。例如在bookmarklets。keep_fargs
-- 默認(rèn)true
。阻止壓縮器干掉那些沒(méi)有用到的函數(shù)參數(shù)。你需要它來(lái)保護(hù)某些依賴Function.length
的函數(shù)。keep_fnames
-- 默認(rèn) false
。傳 true
來(lái)防止壓縮器干掉函數(shù)名。對(duì)那些依賴Function.prototype.name
的函數(shù)很有用。延展閱讀:keep_fnames
混淆選項(xiàng).passes
-- 默認(rèn) 1
。運(yùn)行壓縮的次數(shù)。在某些情況下,用一個(gè)大于1的數(shù)字參數(shù)可以進(jìn)一步壓縮代碼大小。注意:數(shù)字越大壓縮耗時(shí)越長(zhǎng)。keep_infinity
-- 默認(rèn) false
。傳true
以防止壓縮時(shí)把1/0
轉(zhuǎn)成Infinity
,那可能會(huì)在chrome上有性能問(wèn)題。side_effects
-- 默認(rèn) true
. 傳false
禁用丟棄純函數(shù)。如果一個(gè)函數(shù)被調(diào)用前有一段/*@__PURE__*/
or /*#__PURE__*/
注釋,該函數(shù)會(huì)被標(biāo)注為純函數(shù)。例如 /*@__PURE__*/foo();
reserved
(default []
)。 傳一個(gè)不需要混淆的名字的數(shù)組。 Example: ["foo", "bar"]
.
toplevel
(default false
)?;煜切┒x在頂層作用域的名字(默認(rèn)禁用)。?keep_fnames
(default false
)。傳true
的話就不混淆函數(shù)名。對(duì)那些依賴Function.prototype.name
的代碼有用。延展閱讀:keep_fnames
壓縮配置.eval
(default false
)?;煜切┰趙ith或eval中出現(xiàn)的名字。// test.js var globalVar; function funcName(firstLongName, anotherLongName) { var myVariable = firstLongName + anotherLongName; }
var code = fs.readFileSync("test.js", "utf8"); UglifyJS.minify(code).code; // 'function funcName(a,n){}var globalVar;' UglifyJS.minify(code, { mangle: { reserved: ['firstLongName'] } }).code; // 'function funcName(firstLongName,a){}var globalVar;' UglifyJS.minify(code, { mangle: { toplevel: true } }).code; // 'function n(n,a){}var a;'
reserved
(default: []
) -- 不混淆在reserved
數(shù)組里的屬性名.
regex
(default: null
) -— 傳一個(gè)正則,只混淆匹配該正則的屬性名。
keep_quoted
(default: false
) -— 只混淆不在括號(hào)內(nèi)的屬性名.
debug
(default: false
) -— 用原名字來(lái)組成混淆后的名字. 傳空字符串""
來(lái)啟用,或者非空字符串作為debu后綴。(例如"abc"
, foo.bar
=>foo.barabc
)
builtins
(default: false
) -- 傳 true
的話,允許混淆內(nèi)置的DOM屬性名。不推薦使用。
代碼生成器默認(rèn)會(huì)盡量輸出最簡(jiǎn)短的代碼。假如你要美化一下輸出代碼,可以傳--beautify
(-b
)。你也可以傳更多的參數(shù)來(lái)控制輸出代碼:
ascii_only
(default false
) -- 忽略字符串和正則(導(dǎo)致非ascii字符失效)中的Unicode字符。
beautify
(default true
) -- 是否美化輸出代碼。傳-b
的話就是設(shè)成true。假如你想生成最小化的代碼同時(shí)又要用其他設(shè)置來(lái)美化代碼,你可以設(shè)-b beautify=false
。bracketize
(default false
) -- 永遠(yuǎn)在if
, for
,do
, while
, with
后面加上大括號(hào),即使循環(huán)體只有一句。comments
(default false
) -- 傳 true
或 "all"
保留全部注釋,傳 "some"
保留部分,傳正則 (例如 /^!/
) 或者函數(shù)也行。indent_level
(default 4) 縮進(jìn)格數(shù)indent_start
(default 0) -- 每行前面加幾個(gè)空格inline_script
(default false
) -- 避免字符串中出現(xiàn)</script
中的斜杠keep_quoted_props
(default false
) -- 如果啟用,會(huì)保留對(duì)象屬性名的引號(hào)。max_line_len
(default 32000) -- 最大行寬(壓縮后的代碼)space-colon
(default true
) -- 在冒號(hào)后面加空格preamble
(default null
) -- 如果要傳的話,必須是字符串。它會(huì)被加在輸出文檔的前面。sourcemap會(huì)隨之調(diào)整。例如可以用來(lái)插入版權(quán)信息。preserve_line
(default false
) -- 傳 true
就保留空行,但只在beautify
設(shè)為false
時(shí)有效。?quote_keys
(default false
) -- 傳true
的話會(huì)在對(duì)象所有的鍵加上括號(hào)quote_style
(default 0
) -- 影響字符串的括號(hào)格式(也會(huì)影響屬性名和指令)。0
-- 傾向使用雙引號(hào),字符串里還有引號(hào)的話就是單引號(hào)。1
-- 永遠(yuǎn)單引號(hào)2
-- 永遠(yuǎn)雙引號(hào)3
-- 永遠(yuǎn)是本來(lái)的引號(hào)semicolons
(default true
) -- 用分號(hào)分開(kāi)多個(gè)聲明。如果你傳false
,則總會(huì)另起一行,增強(qiáng)輸出文件的可讀性。(gzip前體積更小,gzip后稍大一點(diǎn)點(diǎn))shebang
(default true
) -- 保留開(kāi)頭的 shebang #!
(bash 腳本)width
(default 80) -- 僅在美化時(shí)生效,設(shè)定一個(gè)行寬讓美化器盡量實(shí)現(xiàn)。這會(huì)影響行中文字的數(shù)量(不包括縮進(jìn))。當(dāng)前本功能實(shí)現(xiàn)得不是非常好,但依然讓美化后的代碼可讀性大大增強(qiáng)。wrap_iife
(default false
) --傳true
的話,把立即執(zhí)行函數(shù)括起來(lái)。 更多詳情看這里 #0你可以傳入--comments
讓輸出文件中保留某些注釋。默認(rèn)時(shí)會(huì)保留JSDoc-style的注釋(包含"@preserve","@license" 或 "@cc_on"(為IE所編譯))。你可以傳入--comments all
來(lái)保留全部注釋,或者傳一個(gè)合法的正則來(lái)保留那些匹配到的注釋。例如--comments /^!/
會(huì)保留/*! Copyright Notice */
這樣的注釋。
注意,無(wú)論如何,總會(huì)有些注釋在某些情況下會(huì)丟失。例如:
function f() { /** @preserve Foo Bar */ function g() { // this function is never called } return something(); }
即使里面帶有"@preserve",注釋依然會(huì)被丟棄。因?yàn)閮?nèi)部的函數(shù)g
(注釋所依附的抽象語(yǔ)法樹(shù)節(jié)點(diǎn))沒(méi)有被引用、會(huì)被壓縮器干掉。
書寫版權(quán)信息(或其他需要在輸出文件中保留的信息)的最安全位置是全局節(jié)點(diǎn)。
unsafe``compress
配置unsafe
compress
option在某些刻意營(yíng)造的案例中,啟用某些轉(zhuǎn)換有可能會(huì)打斷代碼的邏輯,但絕大部分情況下是安全的。你可能會(huì)想嘗試一下,因?yàn)檫@畢竟會(huì)減少文件體積。以下是某些例子:
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
(假如作用域中有一個(gè)變量名叫"undefined";我們這么做是因?yàn)樽兞棵麜?huì)被混淆成單字符)
Uglify會(huì)假設(shè)全局變量都是常量(不管是否在局部域中定義了),你可以用--define
(-d
)來(lái)實(shí)現(xiàn)定義全局變量。例如你傳--define DEBUG=false
,UglifyJS會(huì)在輸出中干掉下面代碼:
if (DEBUG) { console.log("debug stuff"); }
你可以像--define env.DEBUG=false
這樣寫嵌套的常量。
在干掉那些永否的條件語(yǔ)句以及不可達(dá)代碼時(shí),UglifyJS會(huì)給出警告。現(xiàn)在沒(méi)有選項(xiàng)可以禁用此特性,但你可以設(shè)置 warnings=false
來(lái)禁掉所有警告。
另一個(gè)定義全局常量的方法是,在一個(gè)的文檔中定義,再引入到構(gòu)建中。例如你有一個(gè)這樣的build/defines.js
:
const DEBUG = false; const PRODUCTION = true; // 等等
這樣構(gòu)建你的代碼:
uglifyjs build/defines.js js/foo.js js/bar.js... -c
UglifyJS會(huì)注意到這些常量。因?yàn)樗鼈儫o(wú)法改變,所以它們會(huì)被認(rèn)為是沒(méi)被引用而被照樣干掉。如果你用const
聲明,構(gòu)建后還會(huì)被保留。如果你的運(yùn)行環(huán)境低于ES6、不支持const
,請(qǐng)用var
聲明加上reduce_vars
設(shè)置(默認(rèn)啟用)來(lái)實(shí)現(xiàn)。
編譯條件語(yǔ)句API
你也可以通過(guò)程序API來(lái)設(shè)置編譯配置。其中有差別的是一個(gè)壓縮器屬性global_defs
:
var result = UglifyJS.minify(fs.readFileSync("input.js", "utf8"), { compress: { dead_code: true, global_defs: { DEBUG: false } } });
在global_defs
配"@"
前綴的表達(dá)式,UglifyJS才會(huì)替換成語(yǔ)句表達(dá)式:
UglifyJS.minify("alert('hello');", { compress: { global_defs: { "@alert": "console.log" } } }).code; // returns: 'console.log("hello");'
否則會(huì)替換成字符串:
UglifyJS.minify("alert('hello');", { compress: { global_defs: { "alert": "console.log" } } }).code; // returns: '"console.log"("hello");'
minify()
獲得原生UglifyJS astminify()
// 例子: 只解析代碼,獲得原生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 是字符串格式的最小化后的代碼
可以通過(guò)TreeWalker
和TreeTransformer
分別橫截(?transversal)和轉(zhuǎn)換原生AST。
UglifyJS有自己的抽象語(yǔ)法樹(shù)格式;為了某些現(xiàn)實(shí)的原因 我們無(wú)法在內(nèi)部輕易地改成使用SpiderMonkey AST。但UglifyJS現(xiàn)在有了一個(gè)可以輸入SpiderMonkeyAST的轉(zhuǎn)換器。 例如Acorn ,這是一個(gè)超級(jí)快的生成SpiderMonkey AST的解釋器。它帶有一個(gè)實(shí)用的迷你CLI,能解釋一個(gè)文件、把AST轉(zhuǎn)存為JSON并標(biāo)準(zhǔn)輸出??梢赃@樣用UglifyJS來(lái)壓縮混淆:
acorn file.js | uglifyjs --spidermonkey -m -c
-p --spidermonkey
選項(xiàng)能讓UglifyJS知道輸入文件并非JavaScript,而是SpiderMonkey AST生成的JSON代碼。這事我們不用自己的解釋器,只把AST轉(zhuǎn)成我們內(nèi)部AST。
更有趣的是,我們加了 -p --acorn
選項(xiàng)來(lái)使用Acorn解釋所有代碼。如果你傳入這個(gè)選項(xiàng),UglifyJS會(huì)require("acorn")
Acorn確實(shí)非??欤?50k代碼原來(lái)要380ms,現(xiàn)在只需250ms),但轉(zhuǎn)換Acorn產(chǎn)生的SpiderMonkey樹(shù)會(huì)額外花費(fèi)150ms。所以總共比UglifyJS自己的解釋器還要多花一點(diǎn)時(shí)間。
很少人知道,對(duì)大多數(shù)js代碼而言,其實(shí)移除空格和混淆符號(hào)已經(jīng)占了減少代碼體積之中到的95%--不必細(xì)致地轉(zhuǎn)換。簡(jiǎn)單地禁用壓縮compress
能加快UglifyJS的構(gòu)建速度三四倍。我們可以比較一下 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. |
在CLI中,這樣啟用快速最小化模式:
uglifyjs file.js -m
API這樣用:
UglifyJS.minify(code, { compress: false, mangle: true });
相關(guān)文章:
JS文件壓縮成PNG圖像存儲(chǔ)方法
壓縮文件解壓器: 文件解壓壓縮
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com