Add passes compress option. Fix duplicate compress warnings.
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
11
test/mocha/minify.js
Normal 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}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user