implement --module (#5462)

This commit is contained in:
Alex Lam S.L
2022-05-23 22:45:47 +01:00
committed by GitHub
parent 740f93f5a9
commit c82fc1ef71
8 changed files with 45 additions and 12 deletions

View File

@@ -118,6 +118,7 @@ a double dash to prevent input files being used as option arguments:
--keep-fargs Do not mangle/drop function arguments. --keep-fargs Do not mangle/drop function arguments.
--keep-fnames Do not mangle/drop function names. Useful for --keep-fnames Do not mangle/drop function names. Useful for
code relying on Function.prototype.name. code relying on Function.prototype.name.
--module Process input as ES module (implies --toplevel)
--name-cache <file> File to hold mangled name mappings. --name-cache <file> File to hold mangled name mappings.
--self Build UglifyJS as a library (implies --wrap UglifyJS) --self Build UglifyJS as a library (implies --wrap UglifyJS)
--source-map [options] Enable source map/specify source map options: --source-map [options] Enable source map/specify source map options:
@@ -517,6 +518,9 @@ if (result.error) throw result.error;
- `mangle.properties` (default: `false`) — a subcategory of the mangle option. - `mangle.properties` (default: `false`) — a subcategory of the mangle option.
Pass an object to specify custom [mangle property options](#mangle-properties-options). Pass an object to specify custom [mangle property options](#mangle-properties-options).
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
- `nameCache` (default: `null`) — pass an empty object `{}` or a previously - `nameCache` (default: `null`) — pass an empty object `{}` or a previously
used `nameCache` object if you wish to cache mangled variable and used `nameCache` object if you wish to cache mangled variable and
property names across multiple invocations of `minify()`. Note: this is property names across multiple invocations of `minify()`. Note: this is
@@ -728,6 +732,9 @@ to be `false` and all symbol names will be omitted.
- `merge_vars` (default: `true`) — combine and reuse variables. - `merge_vars` (default: `true`) — combine and reuse variables.
- `module` (default: `false`) — set to `true` if you wish to process input as
ES module, i.e. implicit `"use strict";` alongside with `toplevel` enabled.
- `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions" - `negate_iife` (default: `true`) — negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the where the return value is discarded, to avoid the parens that the
code generator would insert. code generator would insert.

View File

@@ -107,6 +107,7 @@ function process_option(name, no_value) {
" --ie Support non-standard Internet Explorer.", " --ie Support non-standard Internet Explorer.",
" --keep-fargs Do not mangle/drop function arguments.", " --keep-fargs Do not mangle/drop function arguments.",
" --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.", " --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.",
" --module Process input as ES module (implies --toplevel)",
" --name-cache <file> File to hold mangled name mappings.", " --name-cache <file> File to hold mangled name mappings.",
" --rename Force symbol expansion.", " --rename Force symbol expansion.",
" --no-rename Disable symbol expansion.", " --no-rename Disable symbol expansion.",
@@ -152,6 +153,7 @@ function process_option(name, no_value) {
case "annotations": case "annotations":
case "ie": case "ie":
case "ie8": case "ie8":
case "module":
case "timings": case "timings":
case "toplevel": case "toplevel":
case "v8": case "v8":

View File

@@ -80,6 +80,7 @@ function Compressor(options, false_by_default) {
keep_infinity : false, keep_infinity : false,
loops : !false_by_default, loops : !false_by_default,
merge_vars : !false_by_default, merge_vars : !false_by_default,
module : false,
negate_iife : !false_by_default, negate_iife : !false_by_default,
objects : !false_by_default, objects : !false_by_default,
optional_chains : !false_by_default, optional_chains : !false_by_default,
@@ -97,7 +98,7 @@ function Compressor(options, false_by_default) {
switches : !false_by_default, switches : !false_by_default,
templates : !false_by_default, templates : !false_by_default,
top_retain : null, top_retain : null,
toplevel : !!(options && options["top_retain"]), toplevel : !!(options && (options["module"] || options["top_retain"])),
typeofs : !false_by_default, typeofs : !false_by_default,
unsafe : false, unsafe : false,
unsafe_comps : false, unsafe_comps : false,
@@ -130,6 +131,7 @@ function Compressor(options, false_by_default) {
var escaped = def.escaped; var escaped = def.escaped;
return escaped && escaped.depth != 1; return escaped && escaped.depth != 1;
}; };
if (this.options["module"]) this.directives["use strict"] = true;
var pure_funcs = this.options["pure_funcs"]; var pure_funcs = this.options["pure_funcs"];
if (typeof pure_funcs == "function") { if (typeof pure_funcs == "function") {
this.pure_funcs = pure_funcs; this.pure_funcs = pure_funcs;
@@ -7360,6 +7362,7 @@ Compressor.prototype.compress = function(node) {
} }
}); });
tt.push(compressor.parent()); tt.push(compressor.parent());
tt.directives = Object.create(compressor.directives);
self.transform(tt); self.transform(tt);
if (self instanceof AST_Lambda if (self instanceof AST_Lambda
&& self.body.length == 1 && self.body.length == 1

View File

@@ -81,13 +81,14 @@ function minify(files, options) {
keep_fargs: false, keep_fargs: false,
keep_fnames: false, keep_fnames: false,
mangle: {}, mangle: {},
module: false,
nameCache: null, nameCache: null,
output: {}, output: {},
parse: {}, parse: {},
rename: undefined, rename: undefined,
sourceMap: false, sourceMap: false,
timings: false, timings: false,
toplevel: false, toplevel: !!(options && options["module"]),
v8: false, v8: false,
validate: false, validate: false,
warnings: false, warnings: false,
@@ -101,6 +102,7 @@ function minify(files, options) {
if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]); if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output", "rename" ]);
if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]); if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle", "rename" ]);
if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle", "rename" ]);
if (options.module) set_shorthand("module", options, [ "compress", "parse" ]);
if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]); if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle", "rename" ]);
if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output", "rename" ]);
if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]); if (options.webkit) set_shorthand("webkit", options, [ "compress", "mangle", "output", "rename" ]);

View File

@@ -237,8 +237,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
newline_before : false, newline_before : false,
regex_allowed : false, regex_allowed : false,
comments_before : [], comments_before : [],
directives : {}, directives : Object.create(null),
directive_stack : [],
read_template : with_eof_error("Unterminated template literal", function(strings) { read_template : with_eof_error("Unterminated template literal", function(strings) {
var s = ""; var s = "";
for (;;) { for (;;) {
@@ -635,23 +634,19 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
}; };
next_token.add_directive = function(directive) { next_token.add_directive = function(directive) {
S.directive_stack[S.directive_stack.length - 1].push(directive); S.directives[directive] = true;
S.directives[directive] = (S.directives[directive] || 0) + 1;
} }
next_token.push_directives_stack = function() { next_token.push_directives_stack = function() {
S.directive_stack.push([]); S.directives = Object.create(S.directives);
} }
next_token.pop_directives_stack = function() { next_token.pop_directives_stack = function() {
var directives = S.directive_stack.pop(); S.directives = Object.getPrototypeOf(S.directives);
for (var i = directives.length; --i >= 0;) {
S.directives[directives[i]]--;
}
} }
next_token.has_directive = function(directive) { next_token.has_directive = function(directive) {
return S.directives[directive] > 0; return !!S.directives[directive];
} }
return next_token; return next_token;
@@ -698,6 +693,7 @@ function parse($TEXT, options) {
expression : false, expression : false,
filename : null, filename : null,
html5_comments : true, html5_comments : true,
module : false,
shebang : true, shebang : true,
strict : false, strict : false,
toplevel : null, toplevel : null,
@@ -2545,6 +2541,7 @@ function parse($TEXT, options) {
return function() { return function() {
var start = S.token; var start = S.token;
var body = []; var body = [];
if (options.module) S.input.add_directive("use strict");
S.input.push_directives_stack(); S.input.push_directives_stack();
while (!is("eof")) while (!is("eof"))
body.push(statement()); body.push(statement());

View File

@@ -0,0 +1 @@
function n(){return this||arguments[0]+arguments[1]}function o(){return this||arguments[0]+arguments[1]}console.log(n(n(1,3),5)),console.log(o(o(2,4),6));

View File

@@ -0,0 +1,13 @@
console.log(function() {
function sum(...params) {
return this || arguments[0] + arguments[1];
}
return sum(sum(1, 3), 5);
}());
console.log(function() {
"use strict";
function sum(...params) {
return this || arguments[0] + arguments[1];
}
return sum(sum(2, 4), 6);
}());

View File

@@ -928,6 +928,14 @@ describe("bin/uglifyjs", function() {
done(); done();
}); });
}); });
it("Should work with --module", function(done) {
var command = uglifyjscmd + " test/input/module/input.js --module -mc";
exec(command, function(err, stdout, stderr) {
if (err) throw err;
assert.strictEqual(stdout, read("test/input/module/expect.js"));
done();
});
});
it("Should compress swarm of unused variables with reasonable performance", function(done) { it("Should compress swarm of unused variables with reasonable performance", function(done) {
var code = [ var code = [
"console.log(function() {", "console.log(function() {",