Add passes compress option. Fix duplicate compress warnings.

This commit is contained in:
kzc
2016-04-12 09:19:38 -04:00
committed by Richard van Velzen
parent e4fa4b109a
commit c55dd5ed74
7 changed files with 66 additions and 44 deletions

View File

@@ -356,6 +356,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
compressor from mangling/discarding function names. Useful for code relying on compressor from mangling/discarding function names. Useful for code relying on
`Function.prototype.name`. `Function.prototype.name`.
- `passes` -- default `1`. Number of times to run compress. Use an
integer argument larger than 1 to further reduce code size in some cases.
Note: raising the number of passes will increase uglify compress time.
### The `unsafe` option ### The `unsafe` option

View File

@@ -423,7 +423,7 @@ async.eachLimit(files, 1, function (file, cb) {
if (COMPRESS) { if (COMPRESS) {
time_it("squeeze", function(){ time_it("squeeze", function(){
TOPLEVEL = TOPLEVEL.transform(compressor); TOPLEVEL = compressor.compress(TOPLEVEL);
}); });
} }

View File

@@ -75,18 +75,36 @@ function Compressor(options, false_by_default) {
screw_ie8 : false, screw_ie8 : false,
drop_console : false, drop_console : false,
angular : false, angular : false,
warnings : true, warnings : true,
global_defs : {} global_defs : {},
passes : 1,
}, true); }, true);
this.warnings_produced = {};
}; };
Compressor.prototype = new TreeTransformer; Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, { merge(Compressor.prototype, {
option: function(key) { return this.options[key] }, option: function(key) { return this.options[key] },
warn: function() { compress: function(node) {
if (this.options.warnings) var passes = +this.options.passes || 1;
AST_Node.warn.apply(AST_Node, arguments); for (var pass = 0; pass < passes && pass < 3; ++pass) {
if (pass > 0) node.clear_opt_flags();
node = node.transform(this);
}
return node;
},
warn: function(text, props) {
if (this.options.warnings) {
// only emit unique warnings
var message = string_template(text, props);
if (!(message in this.warnings_produced)) {
this.warnings_produced[message] = true;
AST_Node.warn.apply(AST_Node, arguments);
}
}
},
clear_warnings: function() {
this.warnings_produced = {};
}, },
before: function(node, descend, in_list) { before: function(node, descend, in_list) {
if (node._squeezed) return node; if (node._squeezed) return node;
@@ -129,6 +147,15 @@ merge(Compressor.prototype, {
return this.print_to_string() == node.print_to_string(); return this.print_to_string() == node.print_to_string();
}); });
AST_Node.DEFMETHOD("clear_opt_flags", function(){
this.walk(new TreeWalker(function(node){
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
node._squeezed = false;
node._optimized = false;
}
}));
});
function make_node(ctor, orig, props) { function make_node(ctor, orig, props) {
if (!props) props = {}; if (!props) props = {};
if (orig) { if (orig) {
@@ -392,10 +419,7 @@ merge(Compressor.prototype, {
var_defs_removed = true; var_defs_removed = true;
} }
// Further optimize statement after substitution. // Further optimize statement after substitution.
stat.walk(new TreeWalker(function(node){ stat.clear_opt_flags();
delete node._squeezed;
delete node._optimized;
}));
compressor.warn("Replacing " + (is_constant ? "constant" : "variable") + compressor.warn("Replacing " + (is_constant ? "constant" : "variable") +
" " + var_name + " [{file}:{line},{col}]", node.start); " " + var_name + " [{file}:{line},{col}]", node.start);

View File

@@ -39,7 +39,7 @@ non_hoisted_function_after_return_2a: {
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true, hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true, evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
if_return: true, join_vars: true, cascade: true, side_effects: true, if_return: true, join_vars: true, cascade: true, side_effects: true,
collapse_vars: false collapse_vars: false, passes: 2
} }
input: { input: {
function foo(x) { function foo(x) {
@@ -57,20 +57,11 @@ non_hoisted_function_after_return_2a: {
} }
} }
expect: { expect: {
// NOTE: Output is correct, but suboptimal. Not a regression. Can be improved in future.
// This output is run through non_hoisted_function_after_return_2b with same flags.
function foo(x) { function foo(x) {
if (x) { return bar(x ? 1 : 2);
return bar(1);
} else {
return bar(2);
var b;
}
var c = bar(3);
function bar(x) { function bar(x) {
return 7 - x; return 7 - x;
} }
return b || c;
} }
} }
expect_warnings: [ expect_warnings: [
@@ -79,7 +70,12 @@ non_hoisted_function_after_return_2a: {
"WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]" "WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]"
] ]
} }
@@ -91,7 +87,6 @@ non_hoisted_function_after_return_2b: {
collapse_vars: false collapse_vars: false
} }
input: { input: {
// Note: output of test non_hoisted_function_after_return_2a run through compress again
function foo(x) { function foo(x) {
if (x) { if (x) {
return bar(1); return bar(1);
@@ -107,31 +102,20 @@ non_hoisted_function_after_return_2b: {
} }
} }
expect: { expect: {
// the output we would have liked to see from non_hoisted_function_after_return_2a
function foo(x) { function foo(x) {
return bar(x ? 1 : 2); return bar(x ? 1 : 2);
function bar(x) { return 7 - x; } function bar(x) { return 7 - x; }
} }
} }
expect_warnings: [ expect_warnings: [
// Notice that some warnings are repeated by multiple compress passes. // duplicate warnings no longer emitted
// Not a regression. There is room for improvement here. "WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
// Warnings should be cached and only output if unique. "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]", "WARN: Dropping unused variable b [test/compress/issue-1034.js:95,20]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]", "WARN: Dropping unused variable c [test/compress/issue-1034.js:97,16]"
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:102,12]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:102,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:106,12]",
"WARN: Dropping unreachable code [test/compress/issue-1034.js:100,16]",
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:100,16]",
"WARN: Dropping unused variable b [test/compress/issue-1034.js:100,20]",
"WARN: Dropping unused variable c [test/compress/issue-1034.js:102,16]"
] ]
} }

11
test/mocha/minify.js Normal file
View File

@@ -0,0 +1,11 @@
var Uglify = require('../../');
var assert = require("assert");
describe("minify", function() {
it("Should test basic sanity of minify with default options", function() {
var js = 'function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }';
var result = Uglify.minify(js, {fromString: true});
assert.strictEqual(result.code, 'function foo(n){return n?3:7}');
});
});

View File

@@ -110,7 +110,7 @@ function run_compress_tests() {
if (test.mangle_props) { if (test.mangle_props) {
input = U.mangle_properties(input, test.mangle_props); input = U.mangle_properties(input, test.mangle_props);
} }
var output = input.transform(cmp); var output = cmp.compress(input);
output.figure_out_scope(); output.figure_out_scope();
if (test.mangle) { if (test.mangle) {
output.compute_char_frequency(test.mangle); output.compute_char_frequency(test.mangle);

View File

@@ -78,7 +78,7 @@ exports.minify = function(files, options) {
UglifyJS.merge(compress, options.compress); UglifyJS.merge(compress, options.compress);
toplevel.figure_out_scope(); toplevel.figure_out_scope();
var sq = UglifyJS.Compressor(compress); var sq = UglifyJS.Compressor(compress);
toplevel = toplevel.transform(sq); toplevel = sq.compress(toplevel);
} }
// 3. mangle properties // 3. mangle properties