UgifyJS 3
UglifyJS é un analizador, minificador, compresor e ferramentas de embelecemento de JavaScript.
Nota:
uglify-js@3ten unha API e unha CLI simplificadas que non son compatibles conuglify-js@2.- A documentación para
2.xas versións de UgliifyJS pódese atopar aquí . uglify-jssó admite JavaScript (ECMAScript 5).- Para minificar ECMAScript 2015 ou superior, transpile usando ferramentas como Babel .
Instalar
Primeiro asegúrate de ter instalada a última versión de node.js (é posible que teñas que reiniciar o teu ordenador despois deste paso).
Desde NPM para usar como aplicación de liña de comandos:
1npm install uglify-js -g
Desde NPM para uso programático:
1npm install uglify-js
Uso da liña de comandos
1uglifyjs [input files] [options]
UglifyJS pode tomar varios ficheiros de entrada. Recoméndase que pases primeiro os ficheiros de entrada e despois pases as opcións. UglifyJS analizará os ficheiros de entrada en secuencia e aplicará calquera opción de compresión. Os ficheiros analízanse no mesmo ámbito global, é dicir, unha referencia dun ficheiro a algunha variable/función declarada noutro ficheiro coincidirá correctamente.
Se non se especifica ningún ficheiro de entrada, UgliifyJS lerá desde STDIN.
Se queres pasar as túas opcións antes que os ficheiros de entrada, separa os dous cun guión dobre para evitar que os ficheiros de entrada se utilicen como argumentos de opción:
1uglifyjs --compress --mangle -- input.js
Command line options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 -h, --help Print usage information.
`--help options` for details on available options.
-V, --version Print version number.
-p, --parse <options> Specify parser options:
`acorn` Use Acorn for parsing.
`bare_returns` Allow return outside of functions.
Useful when minifying CommonJS
modules and Userscripts that may
be anonymous function wrapped (IIFE)
by the .user.js engine `caller`.
`expression` Parse a single expression, rather than
a program (for parsing JSON).
`spidermonkey` Assume input files are SpiderMonkey
AST format (as JSON).
-c, --compress [options] Enable compressor/specify compressor options:
`pure_funcs` List of functions that can be safely
removed when their return values are
not used.
-m, --mangle [options] Mangle names/specify mangler options:
`reserved` List of names that should not be mangled.
--mangle-props [options] Mangle properties/specify mangler options:
`builtins` Mangle property names that overlaps
with standard JavaScript globals.
`debug` Add debug prefix and suffix.
`domprops` Mangle property names that overlaps
with DOM properties.
`keep_quoted` Only mangle unquoted properties.
`regex` Only mangle matched property names.
`reserved` List of names that should not be mangled.
-b, --beautify [options] Beautify output/specify output options:
`beautify` Enabled with `--beautify` by default.
`preamble` Preamble to prepend to the output. You
can use this to insert a comment, for
example for licensing information.
This will not be parsed, but the source
map will adjust for its presence.
`quote_style` Quote style:
0 - auto
1 - single
2 - double
3 - original
`wrap_iife` Wrap IIFEs in parenthesis. Note: you may
want to disable `negate_iife` under
compressor options.
-o, --output <file> Output file path (default STDOUT). Specify `ast` or
`spidermonkey` to write UglifyJS or SpiderMonkey AST
as JSON to STDOUT respectively.
--comments [filter] Preserve copyright comments in the output. By
default this works like Google Closure, keeping
JSDoc-style comments that contain "@license" or
"@preserve". You can optionally pass one of the
following arguments to this flag:
- "all" to keep all comments
- a valid JS RegExp like `/foo/` or `/^!/` to
keep only matching comments.
Note that currently not *all* comments can be
kept when compression is on, because of dead
code removal or cascading statements into
sequences.
--config-file <file> Read `minify()` options from JSON file.
-d, --define <expr>[=value] Global definitions.
--ie8 Support non-standard Internet Explorer 8.
Equivalent to setting `ie8: true` in `minify()`
for `compress`, `mangle` and `output` options.
By default UglifyJS will not try to be IE-proof.
--keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name.
--name-cache <file> File to hold mangled name mappings.
--self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options:
`base` Path to compute relative paths from input files.
`content` Input source map, useful if you're compressing
JS that was generated from some other original
code. Specify "inline" if the source map is
included within the sources.
`filename` Name and/or location of the output source.
`includeSources` Pass this flag if you want to include
the content of source files in the
source map as sourcesContent property.
`root` Path to the original source to be included in
the source map.
`url` If specified, path to the source map to append in
`//# sourceMappingURL`.
--timings Display operations run time on STDERR.
--toplevel Compress and/or mangle variables in top level scope.
--verbose Print diagnostic messages.
--warn Print warning messages.
--wrap <name> Embed everything in a big function, making the
“exports” and “global” variables available. You
need to pass an argument to this option to
specify the name that your module will take
when included in, say, a browser.
Especifique --output( -o) para declarar o ficheiro de saída. Se non, a saída pasa a STDOUT.
Opcións do mapa fonte da CLI
UglifyJS pode xerar un ficheiro de mapa de orixe, que é moi útil para depurar o teu JavaScript comprimido. Para obter un mapa de orixe, pasa
--source-map --output output.js(o mapa de orixe escribirase en
output.js.map).
Opcións adicionais:
--source-map "filename='<NAME>'"para especificar o nome do mapa de orixe.--source-map "root='<URL>'"para pasar o URL onde se poden atopar os ficheiros orixinais.--source-map "url='<URL>'"para especificar o URL onde se pode atopar o mapa de orixe. En caso contrario, UglifyJS asume queX-SourceMapse está a usar HTTP e omitirá a//# sourceMappingURL=directiva.
Por exemplo:
1
2
3uglifyjs js/file1.js js/file2.js \
-o foo.min.js -c -m \
--source-map "root='http://foo.com/src',url='foo.min.js.map'"
O anterior comprimirá e destrozará file1.jse file2.js, soltará a saída foo.min.jse o mapa de orixe en foo.min.js.map. A asignación de orixe farase referencia a http://foo.com/src/js/file1.jse
http://foo.com/src/js/file2.js(de feito listarase http://foo.com/src
como raíz do mapa de orixe e os ficheiros orixinais como js/file1.jse
js/file2.js).
Composed source map
Cando estás comprimindo código JS que saíu un compilador como CoffeeScript, a asignación ao código JS non será demasiado útil. Pola contra, queres volver a mapear o código orixinal (por exemplo, CoffeeScript). UglifyJS ten un opción para tomar un mapa de orixe de entrada. Asumindo que tes unha asignación de CoffeeScript → JS compilado, UglifyJS pode xerar un mapa desde CoffeeScript → JS comprimido asignando cada token do JS compilado á súa localización orixinal.
Para usar esta función pase --source-map "content='/path/to/input/source.map'"
ou --source-map "content=inline"se o mapa de orixe está incluído en liña coas fontes.
Opcións de compresión da CLI
Debes pasar --compress( -c) para activar o compresor. Opcionalmente podes pasar unha lista de opcións de compresión separadas por comas .
As opcións están na forma foo=bar, ou só foo(esta última implica unha opción booleana que quere configurar true; é efectivamente un atallo para foo=true).
Exemplo:
1uglifyjs file.js -c toplevel,sequences=false
Opcións de mangle CLI
Para activar o mangler, cómpre pasar --mangle( -m). Admítense as seguintes opcións (separadas por comas):
toplevel(predeterminadofalse) -- destroza os nomes declarados no ámbito de nivel superior.eval(predeterminadofalse) -- destroza os nomes visibles nos ámbitos onde se usaevalou .with
Cando a manipulación está activada pero queres evitar que determinados nomes sexan destrozados, podes declarar eses nomes con --mangle reserved— pase unha lista de nomes separados por comas. Por exemplo:
1uglifyjs ... -m reserved=['$','require','exports']
para evitar que se cambien os nomes require, exportse .$
CLI que modifica os nomes de propiedade ( --mangle-props)
Nota: ESTE PROBABLEMENTE ROMPE O TEU CÓDIGO. A manipulación de nomes de propiedade é un paso separado, diferente da manipulación de nomes de variables. Pasa
--mangle-propspara activala. Destrozará todas as propiedades do código de entrada, a excepción das propiedades DOM integradas e as propiedades do JavaScript principal. clases. Por exemplo:
1
2
3
4
5
6
7
8
9
10
11// 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());
Destruír todas as propiedades (excepto JavaScript builtins):
1$ uglifyjs example.js -c -m --mangle-props
1var x={o:0,_:1,l:function(){return this._+this.o}};x.t=2,x.o=3,console.log(x.l());
Destroza todas as propiedades excepto as reservedpropiedades:
1$ uglifyjs example.js -c -m --mangle-props reserved=[foo_,bar_]
1var x={o:0,foo_:1,_:function(){return this.foo_+this.o}};x.bar_=2,x.o=3,console.log(x._());
Destroza todas as propiedades que coincidan con regex:
1$ uglifyjs example.js -c -m --mangle-props regex=/_$/
1var x={o:0,_:1,calc:function(){return this._+this.o}};x.l=2,x.o=3,console.log(x.calc());
Opcións de combinación de propiedades de mangle:
1$ uglifyjs example.js -c -m --mangle-props regex=/_$/,reserved=[bar_]
1var x={o:0,_:1,calc:function(){return this._+this.o}};x.bar_=2,x.o=3,console.log(x.calc());
Para que isto sexa útil, evitamos manipular os nomes JS estándar por defecto ( --mangle-props builtinspara anular).
Ofrécese un ficheiro de exclusión predeterminado no tools/domprops.jsonque debería cubrir a maioría das propiedades estándar de JS e DOM definidas en varios navegadores. Pase
--mangle-props dompropspara desactivar esta función.
Pódese usar unha expresión regular para definir que nomes de propiedade deben ser alterados. Por exemplo, --mangle-props regex=/^_/só se modificarán os nomes de propiedade que comecen cun guión baixo.
Cando comprimes varios ficheiros usando esta opción, para que funcionen xuntos ao final, debemos asegurarnos de que unha propiedade sexa alterada co mesmo nome en todos eles. Para iso, pass --name-cache filename.json
e UglifyJS manterá estas asignacións nun ficheiro que despois se pode reutilizar. Inicialmente debería estar baleiro. Exemplo:
1
2
3$ 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
Agora, part1.jse part2.jsserán consistentes entre si en termos de nomes de propiedade mutilados.
Non é necesario usar a caché de nomes se comprimes todos os teus ficheiros nunha única chamada a UglifyJS.
Destrozando nomes sen comiñas ( --mangle-props keep_quoted)
Usar o nome da propiedade entre comiñas ( o["foo"]) reserva o nome da propiedade ( foo) para que non se destrúe en todo o script aínda que se use nun estilo sen comiñas ( o.foo). Exemplo:
1
2
3
4
5
6
7// stuff.js
var o = {
"foo": 1,
bar: 3
};
o.foo += o.bar;
console.log(o.foo);
1$ uglifyjs stuff.js --mangle-props keep_quoted -c -m
1var o={foo:1,o:3};o.foo+=o.o,console.log(o.foo);
Debugging property name mangling
Tamén podes pasar --mangle-props debugpara alterar os nomes das propiedades sen ocultalos por completo. Por exemplo, a propiedade o.foo
modificaríase o._$foo$_con esta opción. Isto permite destrozar as propiedades dunha base de código grande, aínda que podes depurar o código e identificar onde se rompen as cousas.
1$ uglifyjs stuff.js --mangle-props debug -c -m
1var o={_$foo$_:1,_$bar$_:3};o._$foo$_+=o._$bar$_,console.log(o._$foo$_);
Tamén podes pasar un sufixo personalizado usando --mangle-props debug=XYZ. Entón isto cambiaría o.fooa o._$foo$XYZ_. Podes cambialo cada vez que compiles un script para identificar como se destrozou unha propiedade. Unha técnica é pasar un número aleatorio a cada compilación para simular o cambio de alteración con diferentes entradas (por exemplo, mentres actualiza o script de entrada con novas propiedades) e para axudar a identificar erros como escribir chaves destrozadas no almacenamento.
Referencia da API
Asumindo a instalación mediante NPM, pode cargar UglifyJS na súa aplicación deste xeito:
1var UglifyJS = require("uglify-js");
Hai unha única función de alto nivel, minify(code, options), que realizará todas as fases de minificación dun xeito configurable. Por defecto minify()activará as opcións compress
e mangle. Exemplo:
1
2
3
4var 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}
Podes minifymáis dun ficheiro JavaScript á vez usando un obxecto para o primeiro argumento onde as claves son nomes de ficheiros e os valores son código fonte:
1
2
3
4
5
6
7var 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));
A toplevelopción:
1
2
3
4
5
6
7
8var 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);
A nameCacheopción:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var 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));
Pode conservar a caché de nomes no sistema de ficheiros do seguinte xeito:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var 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");
Un exemplo dunha combinación de minify()opcións:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var 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);"
Para producir avisos:
1
2
3
4
5
6var 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}
Un exemplo de erro:
1
2
3var 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}
Nota: a diferenza de uglify-js@2.x, a 3.xAPI non xera erros. Para conseguir un efecto similar, pódese facer o seguinte:
1
2var result = UglifyJS.minify(code, options);
if (result.error) throw result.error;
Minimizar as opcións
warnings(predeterminadofalse) — pasetruepara devolver avisos de compresor enresult.warnings. Use o valor"verbose"para avisos máis detallados.parse(predeterminado{}): pase un obxecto se quere especificar algunhas opcións de análise adicionais .compress(predeterminado{}): pasefalsepara omitir a compresión por completo. Pase un obxecto para especificar opcións de compresión personalizadas .mangle(predeterminadotrue): pasefalsepara omitir os nomes alterados ou pase un obxecto para especificar as opcións de destrozo (consulte a continuación).mangle.properties(predeterminadofalse) — unha subcategoría da opción de mangle. Pase un obxecto para especificar opcións de propiedade de mangle personalizadas .
output(predeterminadonull) — pasa un obxecto se queres especificar opcións de saída adicionais . Os valores predeterminados están optimizados para a mellor compresión.sourceMap(predeterminadofalse): pase un obxecto se desexa especificar as opcións do mapa de orixe .toplevel(predeterminadofalse) - establécesetruecomo se desexa activar a manipulación de nomes de funcións e variables de nivel superior e eliminar as variables e funcións non utilizadas.nameCache(predeterminadonull) - pase un obxecto baleiro{}ou unnameCacheobxecto usado anteriormente se desexa almacenar na memoria caché os nomes de variables e propiedades alterados en varias invocacións deminify(). Nota: esta é unha propiedade de lectura/escritura.minify()lerá o estado da caché de nomes deste obxecto e actualizalo. durante a minificación para que o usuario poida reutilizalo ou persistir externamente.ie8(predeterminadofalse): configurado paratrueadmitir IE8.keep_fnames(predeterminado:false) - pasetruepara evitar que se descarten ou destrúan os nomes das funcións. Útil para o código que depende deFunction.prototype.name.
Minimizar a estrutura de opcións
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25{
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,
warnings: false,
}
Source map options
Para xerar un mapa de orixe:
1
2
3
4
5
6
7
8var 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
Teña en conta que o mapa de orixe non se garda nun ficheiro, só se devolve en
result.map. O valor pasado sourceMap.urlsó se usa para establecer
//# sourceMappingURL=out.js.mapen result.code. O valor de
filenamesó se usa para definir fileo atributo (consulte a especificación ) no ficheiro de mapa de orixe.
Podes configurar a opción sourceMap.urlpara ser "inline"e engadirase o mapa fonte ao código.
Tamén pode especificar a propiedade sourceRoot para incluír no mapa de orixe:
1
2
3
4
5
6var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
sourceMap: {
root: "http://example.com/src",
url: "out.js.map"
}
});
Se estás comprimindo JavaScript compilado e tes un mapa de orixe para el, podes usar sourceMap.content:
1
2
3
4
5
6
7var 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`
Se estás usando a X-SourceMapcabeceira no seu lugar, podes simplemente omitir sourceMap.url.
Opcións de análise
bare_returns(predeterminadofalse) -- admitereturndeclaracións de nivel superiorhtml5_comments(predeterminadotrue)shebang(predeterminadotrue) -- soporte#!commandcomo primeira liña
Opcións de compresión
arguments(predeterminado:true) -- substituírarguments[index]polo nome do parámetro da función sempre que sexa posible.booleans(predeterminado:true) -- varias optimizacións para o contexto booleano, por exemplo!!a ? b : c → a ? b : ccollapse_vars(predeterminado:true) -- Contraer variables non constantes dun só uso, se os efectos secundarios o permiten.comparisons(predeterminado:true) -- aplique certas optimizacións a nós binarios, por exemplo!(a <= b) → a > b, intentos de negar nós binarios, por exemplo,a = !b && !c && !d && !e → a=!(b||c||d||e)etc.conditionals(predeterminado:true) -- aplica optimizacións paraif-s e expresións condicionaisdead_code(predeterminado:true) -- elimina o código inalcanzabledrop_console(predeterminado:false) -- Pasatruepara descartar chamadas aconsole.*funcións. Se queres eliminar unha chamada de función específica, comoconsole.infoe/ou conservar os efectos secundarios dos argumentos de función despois de soltar a chamada de función, úsaopure_funcsno seu lugar.drop_debugger(predeterminado:true) -- eliminadebugger;instruciónsevaluate(predeterminado:true) -- tenta avaliar expresións constantesexpression(predeterminado:false) -- Pasetruepara preservar os valores de finalización das instrucións do terminal senreturn, por exemplo, nos marcadores.global_defs(predeterminado:{}) -- consulte a compilación condicionalhoist_funs(predeterminado:false) -- declaracións da función de elevaciónhoist_props(predeterminado:true) -- eleva as propiedades de literais de obxectos e matrices constantes a variables normais suxeitas a un conxunto de restricións. Por exemplo:var o={p:1, q:2}; f(o.p, o.q);convértese enf(1, 2);. Nota:hoist_propsfunciona mellor conmangleenabled, acompressopciónpassesdefinida2ou superior e acompressopcióntoplevelactivada.hoist_vars(predeterminado:false) --vardeclaracións de elevación (isto éfalsepor defecto porque parece aumentar o tamaño da saída en xeral)if_return(predeterminado:true) -- optimizacións para if/return e if/continueinline(predeterminado:true) -- chamadas en liña para funcionar conreturninstrución simple/:false--o mesmo que00-- Inline desactivado1-- funcións sinxelas en liña2-- funcións en liña con argumentos3-- funcións en liña con argumentos e variablestrue--o mesmo que3
join_vars(predeterminado: ) -- únete declaraciónstrueconsecutivasvarkeep_fargs(predeterminado:true) -- Evita que o compresor descarte argumentos de funcións non utilizados. Necesitas isto para o código que depende deFunction.length.keep_fnames(predeterminado:false) -- Pasatruepara evitar que o compresor descarte os nomes das funcións. Útil para que o código se basee enFunction.prototype.name. Consulte tamén: akeep_fnamesopción de mangle .keep_infinity(predeterminado:false) -- Pasetruepara evitarInfinityque se comprima en1/0, o que pode causar problemas de rendemento en Chrome.loops(predeterminado:true) -- optimizacións parado,whileeforbucles cando podemos determinar estáticamente a condición.negate_iife(predeterminado:true) -- nega "Expresións de función chamadas inmediatamente" onde se descarta o valor de retorno, para evitar os parénteses que inseriría o xerador de código.passes(predeterminado:1) -- O número máximo de veces para executar comprimir. Nalgúns casos, máis dunha pasada leva a un código comprimido máis. Ten en conta que máis pasadas levarán máis tempo.properties(predeterminado:true) -- reescribe o acceso á propiedade usando a notación de puntos, por exemplofoo["bar"] → foo.barpure_funcs(predeterminado:null) -- Podes pasar unha matriz de nomes e UglifyJS asumirá que esas funcións non producen efectos secundarios. PERIGO: non comprobará se o nome está redefinido no ámbito. Un exemplo de caso aquí, por exemplo.var q = Math.floor(a/b)Se a variableqé non se usa noutro lugar, UglifyJS abandonarao, pero aínda así manterá oMath.floor(a/b), sen saber o que fai. Podes pasarpure_funcs: [ 'Math.floor' ]para informarlle de que esta función non producirá ningún efecto secundario, nese caso descartarase a declaración completa. a implementación actual engade algo de sobrecarga (a compresión será máis lenta). Asegúrate de que os símbolos debaixopure_funcstamén estean baixosmangle.reservedpara evitar destrozos.pure_getters(predeterminado:"strict") -- Se pasatruepor isto, UglifyJS asumirá que o acceso á propiedade do obxecto (por exemplo,foo.baroufoo["bar"]) non ten ningún efecto secundario. Especifique"strict"para tratarfoo.barcomo libre de efectos secundarios só candofooestea seguro de non lanzar, é dicir, nonnullouundefined.reduce_funcs(predeterminado:true) -- Permite que as funcións dun só uso estean integradas como expresións de función cando se permite unha optimización adicional. Activada de forma predeterminada. A opción depende de quereduce_varsestea activada. Algún código execútase máis rápido no motor Chrome V8 se esta opción está desactivada. Non o fai. afectan negativamente a outros navegadores principais.reduce_vars(predeterminado:true) -- Mellora a optimización das variables asignadas e utilizadas como valores constantes.sequences(predeterminado:true) -- une instrucións simples consecutivas mediante o operador de coma. Pódese establecer como un enteiro positivo para especificar o número máximo de secuencias de coma consecutivas que se xerarán. Se esta opción se define como límitetruepredeterminadosequencesé200. Establecer opción parafalseou0para desactivar. Asequenceslonxitude máis pequena é2. Unsequencesvalor de1é equivalente atruee como tal significa200. En raras ocasións, o límite de secuencias predeterminados conduce a tempos de compresión moi lentos, caso en que20se recomenda un valor igual ou inferior.side_effects(predeterminado:true) -- Pasarfalsepara desactivar funcións que se poden eliminar marcadas como "puras". Unha chamada de función márcase como "pura" se unha anotación de comentario/*@__PURE__*/ou/*#__PURE__*/precede inmediatamente á chamada. Por exemplo:/*@__PURE__*/foo();switches(predeterminado:true) -- desduplica e eliminaswitchramas inalcanzablestoplevel(predeterminado:false) -- elimina funcións sen referencia ("funcs") e/ou variables ("vars") no ámbito de nivel superior (falsepor defecto,trueelimina funcións e variables sen referencia)top_retain(predeterminado:null) -- evita que se eliminen funcións e variables específicas de nivel superiorunused(pode ser matriz, separadas por comas, ExpExp ou función. Implicatoplevel)typeofs(predeterminado:true) -- Transfórmasetypeof foo == "undefined"enfoo === void 0. Nota: recoméndase establecer este valorfalsepara IE10 e versións anteriores debido a problemas coñecidos.unsafe(predeterminado:false) -- aplicar transformacións "inseguras" (discusión a continuación)unsafe_comps(predeterminado:false) -- comprime expresións comoa <= basumir que ningún dos operandos pode ser (coaccionado a)NaN.unsafe_Function(predeterminado:false) -- comprimir e destrozarFunction(args, code)cando ambosargsecodeson literais de cadea.unsafe_math(predeterminado:false) -- optimiza expresións numéricas como2 * x * 3into6 * x, que pode dar resultados imprecisos en coma flotante.unsafe_proto(predeterminado:false) -- optimiza expresións comoArray.prototype.slice.call(a)into[].slice.call(a)unsafe_regexp(predeterminado:false) -- permite substitucións de variables conRegExpvalores do mesmo xeito que se fosen constantes.unsafe_undefined(predeterminado:false) -- substitúeovoid 0se hai unha variable nomeadaundefinedno ámbito (o nome da variable será alterado, normalmente reducido a un só carácter)unused(predeterminado:true) -- elimina funcións e variables sen referencia (as asignacións de variables directas sinxelas non contan como referencias a menos que se establezan en"keep_assign")warnings(predeterminado:false) -- mostra avisos ao soltar código inalcanzable ou declaracións non utilizadas, etc.
Mangle opcións
eval(predeterminadofalse) -- Pasatruea destrozar os nomes visibles nos ámbitos onde se usanevalou .withkeep_fnames(predeterminadofalse) -- Pasetruepara non alterar os nomes das funcións. Útil para o código baseado enFunction.prototype.name. Consulte tamén: akeep_fnamesopción de comprimir .reserved(predeterminado[]) -- Pase unha matriz de identificadores que deberían excluírse da manipulación. Exemplo:["foo", "bar"].toplevel(predeterminadofalse) -- Pasatruea mangle os nomes declarados no ámbito de nivel superior.
Exemplos:
1
2
3
4
5// test.js
var globalVar;
function funcName(firstLongName, anotherLongName) {
var myVariable = firstLongName + anotherLongName;
}
1
2
3
4
5
6
7
8
9
10var 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;'
Mangle properties options
builtins(predeterminado:false) -- Utilízasetruepara permitir a alteración das propiedades DOM integradas. Non se recomenda anular esta configuración.debug(predeterminado:false) -- Destroza os nomes co nome orixinal aínda presente. Pasa unha cadea baleira""para activala ou unha cadea non baleira para establecer o sufixo de depuración.keep_quoted(predeterminado:false) -- Destroza só os nomes de propiedade sen comiñas.regex(predeterminado:null) -- Pase un literal de RegExp para modificar só os nomes de propiedade que coincidan coa expresión regular.reserved(predeterminado:[]) -- Non manipular os nomes das propiedades listados nareservedmatriz.
Opcións de saída
O xerador de código tenta producir o código máis curto posible de forma predeterminada. No caso de querer unha saída embelecida, pase --beautify( -b). Opcionalmente, pode pasar argumentos adicionais que controlen a saída do código:
ascii_only(predeterminadofalse) -- escape de caracteres Unicode en cadeas e expresións regulares (afecta ás directivas con caracteres non ascii que non son válidos)beautify(predeterminadotrue) -- se realmente embelece a saída. Ao pasar-bisto establecerase como verdadeiro, pero pode que teñas que pasar-bmesmo cando queiras xerar código minificado, para especificar argumentos adicionais, para que poidas utilizalo-b beautify=falsepara anulalo.braces(predeterminadofalse) -- sempre insira chaves nas instruciónsif,for, ou , aínda que o seu corpo sexa unha única instrucióndo.whilewithcomments(predeterminadofalse) -- pasetrueou"all"para conservar todos os comentarios,"some"para conservar algúns comentarios, unha cadea de expresións regulares (por exemplo,/^!/) ou unha función.indent_level(predeterminado4)indent_start(predeterminado0) -- prefixo todas as liñas con tantos espazosinline_script(predeterminadotrue) -- escape comentarios HTML e a barra inclinada nas ocorrencias de</script>en cadeaskeep_quoted_props(predeterminadofalse) -- cando está activado, impide eliminar as comiñas dos nomes de propiedade nos literais de obxecto.max_line_len(predeterminadofalse) -- lonxitude máxima da liña (para o código feo)preamble(predeterminadonull) -- cando se pasa debe ser unha cadea e antepoñerase literalmente á saída. O mapa de orixe axustarase para este texto. Pódese usar para inserir un comentario que conteña información de licenza, por exemplo.preserve_line(predeterminadofalse) -- pasatruepara conservar liñas, pero só funciona sebeautifyestá configurado comofalse.quote_keys(predeterminadofalse) -- pasetruepara citar todas as claves en obxectos literaisquote_style(predeterminado0) -- estilo de comiña preferido para as cadeas (afecta tamén aos nomes e ás directivas das propiedades citadas):0-- prefire comiñas dobres, cambia a comiñas simples cando hai máis comiñas dobres na propia cadea.0é o mellor para o tamaño do gzip.1-- use sempre comiñas simples2-- use sempre comiñas dobres3-- use sempre as comiñas orixinais
semicolons(predeterminadotrue) -- declaracións separadas con punto e coma. Se pasa,falsesempre que sexa posible, utilizaremos unha liña nova en lugar de punto e coma, o que dará lugar a unha saída máis lexible de código feo (o tamaño antes de gzip pode ser menor; o tamaño despois de gzip é insignificantemente maior).shebang(predeterminadotrue) -- conserva shebang#!no preámbulo (scripts bash)webkit(predeterminadofalse) -- habilite as solucións para os erros de WebKit. Os usuarios de PhantomJS deben establecer esta opción entrue.width(predeterminado80) -- só ten efecto cando o embelecemento está activado, isto especifica un ancho de liña (orientativo) que o embelecedor tentará obedecer. Refírese ao ancho do texto da liña (excluíndo a sangría). Non funciona moi ben actualmente, pero fai que o código xerado por UglifyJS sexa máis lexible.wrap_iife(predeterminadofalse) -- pasetruepara envolver expresións de función invocadas inmediatamente. Consulte #640 para obter máis detalles.
Varios
Keeping copyright notices or other comments
Podes pasar --commentspara conservar certos comentarios na saída. Por defecto, manterá os comentarios de estilo JSDoc que conteñan "@preserve", "@license" ou "@cc_on" (compilación condicional para IE). Podes pasar
--comments allpara manter todos os comentarios ou unha expresión regular de JavaScript válida para manter só os comentarios que coincidan con esta expresión regular. Por exemplo, --comments /^!/
manterase comentarios como /*! Copyright Notice */.
Teña en conta, non obstante, que pode haber situacións nas que se perdan comentarios. Por exemplo:
1
2
3
4
5
6
7function f() {
/** @preserve Foo Bar */
function g() {
// this function is never called
}
return something();
}
Aínda que teña "@preserve", o comentario perderase porque a función interna g(que é o nodo AST ao que está conectado o comentario) é descartada polo compresor como non se fai referencia.
Os comentarios máis seguros onde colocar información de copyright (ou outra información que se debe gardar na saída) son os comentarios adxuntos aos nodos de nivel superior.
A unsafe compressopción
Permite algunhas transformacións que poden romper a lóxica do código nalgúns casos artificiais, pero deberían estar ben para a maioría do código. Quizais queiras probalo no teu propio código, debería reducir o tamaño reducido. Isto é o que ocorre cando esta marca está activada:
new Array(1, 2, 3)ouArray(1, 2, 3)→[ 1, 2, 3 ]new Object()→{}String(exp)ouexp.toString()→"" + expnew Object/RegExp/Function/Error/Array (...)→ descartamos onew
Conditional compilation
Podes usar o interruptor --define( -d) para declarar as variables globais que UglifyJS asumirá como constantes (a non ser que se defina no ámbito). Por exemplo, se pasas --define DEBUG=falseentón, xunto coa eliminación do código morto, UglifyJS descartará o seguinte da saída:
1
2
3if (DEBUG) {
console.log("debug stuff");
}
Podes especificar constantes aniñadas en forma de --define env.DEBUG=false.
UglifyJS avisará de que a condición é sempre falsa e de que se solta o código inalcanzable; polo momento non hai opción para desactivar só este aviso específico, pode pasar warnings=falsepara desactivar todos os avisos.
Outra forma de facelo é declarar os teus globais como constantes nun ficheiro separado e incluílo na compilación. Por exemplo, podes ter un
build/defines.jsficheiro co seguinte:
1
2
3var DEBUG = false;
var PRODUCTION = true;
// etc.
e crea o teu código así:
1uglifyjs build/defines.js js/foo.js js/bar.js... -c
UglifyJS notará as constantes e, dado que non se poden alterar, avaliará as referencias a elas co propio valor e deixará caer o código inalcanzable como é habitual. A compilación conterá as constdeclaracións se as usas. Se estás dirixido a ambientes < ES6 que non not support const, usar varcon reduce_vars(activado por defecto) debería ser suficiente.
Conditional compilation API
Tamén podes usar a compilación condicional a través da API programática. Coa diferenza de que o nome da propiedade é global_defse é unha propiedade do compresor:
1
2
3
4
5
6
7
8var result = UglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
compress: {
dead_code: true,
global_defs: {
DEBUG: false
}
}
});
Para substituír un identificador por unha expresión arbitraria non constante é necesario prefixar a global_defschave con "@"para indicar a UglifyJS que analice o valor como expresión:
1
2
3
4
5
6
7
8UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"@alert": "console.log"
}
}
}).code;
// returns: 'console.log("hello");'
En caso contrario, substituirase como literal de cadea:
1
2
3
4
5
6
7
8UglifyJS.minify("alert('hello');", {
compress: {
global_defs: {
"alert": "console.log"
}
}
}).code;
// returns: '"console.log"("hello");'
Usando Uglify AST nativo conminify()
1
2
3
4
5
6
7
8
9
10
11
12
13// example: parse only, produce native Uglify AST
var result = UglifyJS.minify(code, {
parse: {},
compress: false,
mangle: false,
output: {
ast: true,
code: false // optional - faster if false
}
});
// result.ast contains native Uglify AST
1
2
3
4
5
6
7
8
9
10
11
12
13
14// example: accept native Uglify AST input and then compress and mangle
// to produce both code and native AST.
var result = UglifyJS.minify(ast, {
compress: {},
mangle: {},
output: {
ast: true,
code: true // optional - faster if false
}
});
// result.ast contains native Uglify AST
// result.code contains the minified code in string form.
Working with Uglify AST
A transversal e a transformación da AST nativa pódense realizar mediante
TreeWalkere
TreeTransformer
respectivamente.
ESTree / SpiderMonkey AST
UglifyJS ten o seu propio formato de árbore de sintaxe abstracta; por razóns prácticas non podemos cambiar facilmente a usar o SpiderMonkey AST internamente. Non obstante, UglifyJS ten agora un conversor que pode importar un SpiderMonkey AST.
Por exemplo , Acorn é un analizador súper rápido que produce un SpiderMonkey AST. Ten unha pequena utilidade CLI que analiza un ficheiro e volca o AST en JSON na saída estándar. Para usar UglifyJS para modificar e comprimir isto:
1acorn file.js | uglifyjs -p spidermonkey -m -c
A -p spidermonkeyopción indica a UglifyJS que todos os ficheiros de entrada non son JavaScript, senón código JS descrito en SpiderMonkey AST en JSON. Polo tanto, non usamos o noso propio analizador neste caso, senón que transformamos ese AST no noso AST interno.
Use Acorn for parsing
Máis por diversión, engadín a -p acornopción que usará Acorn para facer todo o análise. Se pasas esta opción, UgliifyJS fará require("acorn").
Acorn é moi rápido (por exemplo, 250 ms en lugar de 380 ms nalgún código de 650 K), pero converter a árbore SpiderMonkey que produce Acorn leva outros 150 ms, polo que en total é un pouco máis que usar o propio analizador de UglifyJS.
Uglify Fast Minify Mode
Non é moi coñecido, pero a eliminación de espazos en branco e a manipulación de símbolos representan o 95 % da redución de tamaño do código reducido para a maioría de JavaScript, non as transformacións de código elaboradas. Pódese simplemente desactivar compresspara acelerar as compilacións de Uglify de 3 a 4 veces. Desta forma rápida mangle... O único modo Uglify ten velocidades de redución e tamaños gzip comparables a
butternut:
| d3.js | reducir o tamaño | tamaño gzip | tempo reducido (segundos) |
|---|---|---|---|
| orixinal | 451.131 | 108.733 | - |
| uglify-js@3.0.24 mangle=falso, comprimir=falso | 316.600 | 85.245 | 0,70 |
| uglify-js@3.0.24 mangle=true, comprimir=false | 220.216 | 72.730 | 1.13 |
| butternut@0.4.6 | 217.568 | 72.738 | 1.41 |
| uglify-js@3.0.24 mangle=true, comprimir=true | 212.511 | 71.560 | 3.36 |
| babili@0.1.4 | 210.713 | 72.140 | 12.64 |
Para activar o modo de minificación rápida desde a CLI, use:
1uglifyjs file.js -m
Para activar o modo de minificación rápida coa API, use:
1UglifyJS.minify(code, { compress: false, mangle: true });
Mapas de orixe e depuración
Sábese que varias compresstransformacións que simplifican, reorganizan, integran e eliminan código teñen un efecto adverso na depuración dos mapas fonte. Espérase que o código está optimizado e que moitas veces non son posibles as asignacións xa que algún código xa non existe. Para obter a máxima fidelidade na fonte. a depuración de mapas desactive a opción Uglify compresse só use mangle.
Compiler assumptions
Para permitir mellores optimizacións, o compilador fai varias suposicións:
.toString()e.valueOf()non teñen efectos secundarios, e para os obxectos incorporados non se anularon.undefined,NaNeInfinitynon se redefiniron externamente.arguments.callee,arguments.callereFunction.prototype.callernon se usan.- O código non espera que o contido
Function.prototype.toString()ouError.prototype.stacksexa algo en particular. - A obtención e configuración de propiedades nun obxecto simple non provoca outros efectos secundarios (usar
.watch()ouProxy). - As propiedades do obxecto pódense engadir, eliminar e modificar (non se evitan con
,
Object.defineProperty(),Object.defineProperties()ou ) .Object.freeze()Object.preventExtensions()Object.seal()
