"reorder_funs" - sort function declarations by complexity

This reduces the size after gzip.  Complexity is (for now) measured simply by counting AST nodes.
This commit is contained in:
Geraint 2016-06-28 15:52:49 +01:00
parent 9676167aac
commit f8dd879873
3 changed files with 65 additions and 5 deletions

View File

@ -326,6 +326,10 @@ to set `true`; it's effectively a shortcut for `foo=true`).
- `hoist_funs` -- hoist function declarations
- `reorder_funs` -- rearrange function declarations in order of increasing
complexity. This has no effect on size before gzip, but often reduces size
after gzip.
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
by default because it seems to increase the size of the output in general)

View File

@ -61,6 +61,7 @@ function Compressor(options, false_by_default) {
loops : !false_by_default,
unused : !false_by_default,
hoist_funs : !false_by_default,
reorder_funs : !false_by_default,
keep_fargs : true,
keep_fnames : false,
hoist_vars : false,
@ -108,14 +109,12 @@ merge(Compressor.prototype, {
},
before: function(node, descend, in_list) {
if (node._squeezed) return node;
var was_scope = false;
if (node instanceof AST_Scope) {
node = node.hoist_declarations(this);
was_scope = true;
}
var was_scope = node instanceof AST_Scope;
descend(node, this);
node = node.optimize(this);
if (was_scope && node instanceof AST_Scope) {
node = node.ast_complexity(this);
node = node.hoist_declarations(this);
node.drop_unused(this);
descend(node, this);
}
@ -152,10 +151,26 @@ merge(Compressor.prototype, {
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
node._squeezed = false;
node._optimized = false;
node._complexity = 0;
}
}));
});
AST_Node.DEFMETHOD("ast_complexity", function(){
var self = this;
var complexity = 0;
self.walk(new TreeWalker(function(node){
if (node._complexity) {
complexity += node._complexity;
return true;
} else {
complexity++;
}
}));
self._complexity = complexity;
return self;
});
function make_node(ctor, orig, props) {
if (!props) props = {};
if (orig) {
@ -1574,6 +1589,14 @@ merge(Compressor.prototype, {
}
);
self = self.transform(tt);
if (compressor.option('reorder_funs')) {
// Moving simpler functions earlier tends to give better gzip compression
hoisted.sort(function (a, b) {
var aComplexity = a._complexity;
var bComplexity = b._complexity;
return (aComplexity - bComplexity) || (a.start.pos - b.start.pos);
});
}
if (vars_found > 0) {
// collect only vars which don't show up in self's arguments list
var defs = [];

View File

@ -0,0 +1,33 @@
reorder_functions_after_optimize: {
options = {
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
reorder_funs:true, keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
}
input: {
function longFun(x, y) {
return [x, y].map(function (x) {
return x*x;
});
}
function medFun(x) {
return 15*x;
}
function shortFun() {
return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;
}
}
expect: {
function shortFun() {
return 55;
}
function medFun(x) {
return 15*x;
}
function longFun(x, y) {
return [x, y].map(function (x) {
return x*x;
});
}
}
}