From f2348dd98baeb7dc3e0542465ede897c15d7cbc9 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Fri, 4 Oct 2013 13:17:25 +0300 Subject: [PATCH] Rename clean_getters to pure_getters; add pure_funcs. --- README.md | 31 ++++++++++++++++++++++++++++++- lib/compress.js | 15 +++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6980878c..3a4d27a5 100644 --- a/README.md +++ b/README.md @@ -184,38 +184,67 @@ you can pass a comma-separated list of options. Options are in the form to set `true`; it's effectively a shortcut for `foo=true`). - `sequences` -- join consecutive simple statements using the comma operator + - `properties` -- rewrite property access using the dot notation, for example `foo["bar"] → foo.bar` + - `dead_code` -- remove unreachable code + - `drop_debugger` -- remove `debugger;` statements + - `unsafe` (default: false) -- apply "unsafe" transformations (discussion below) + - `conditionals` -- apply optimizations for `if`-s and conditional expressions + - `comparisons` -- apply certain optimizations to binary nodes, for example: `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. + - `evaluate` -- attempt to evaluate constant expressions + - `booleans` -- various optimizations for boolean context, for example `!!a ? b : c → a ? b : c` + - `loops` -- optimizations for `do`, `while` and `for` loops when we can statically determine the condition + - `unused` -- drop unreferenced functions and variables + - `hoist_funs` -- hoist function declarations + - `hoist_vars` (default: false) -- hoist `var` declarations (this is `false` by default because it seems to increase the size of the output in general) + - `if_return` -- optimizations for if/return and if/continue + - `join_vars` -- join consecutive `var` statements + - `cascade` -- small optimization for sequences, transform `x, x` into `x` and `x = something(), x` into `x = something()` + - `warnings` -- display warnings when dropping unreachable code or unused declarations etc. + - `negate_iife` -- negate "Immediately-Called Function Expressions" where the return value is discarded, to avoid the parens that the code generator would insert. -- `clean_getters` -- the default is `false`. If you pass `true` for + +- `pure_getters` -- the default is `false`. If you pass `true` for this, UglifyJS will assume that object property access (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. +- `pure_funcs` -- default `null`. You can pass an array of names and + UglifyJS will assume that those functions do not produce side + effects. DANGER: will not check if the name is redefined in scope. + An example case here, for instance `var q = Math.floor(a/b)`. If + variable `q` is not used elsewhere, UglifyJS will drop it, but will + still keep the `Math.floor(a/b)`, not knowing what it does. You can + pass `pure_funcs: [ 'Math.floor' ]` to let it know that this + function won't produce any side effect, in which case the whole + statement would get discarded. The current implementation adds some + overhead (compression will be slower). + ### The `unsafe` option It enables some transformations that *might* break code logic in certain diff --git a/lib/compress.js b/lib/compress.js index 76cbc748..4dd273b5 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -66,7 +66,8 @@ function Compressor(options, false_by_default) { join_vars : !false_by_default, cascade : !false_by_default, side_effects : !false_by_default, - clean_getters : false, + pure_getters : false, + pure_funcs : null, negate_iife : !false_by_default, screw_ie8 : false, @@ -809,6 +810,12 @@ merge(Compressor.prototype, { def(AST_Constant, function(compressor){ return false }); def(AST_This, function(compressor){ return false }); + def(AST_Call, function(compressor){ + var pure = compressor.option("pure_funcs"); + if (!pure) return true; + return pure.indexOf(this.expression.print_to_string()) < 0; + }); + def(AST_Block, function(compressor){ for (var i = this.body.length; --i >= 0;) { if (this.body[i].has_side_effects(compressor)) @@ -855,16 +862,16 @@ merge(Compressor.prototype, { return false; }); def(AST_Dot, function(compressor){ - if (!compressor.option("clean_getters")) return true; + if (!compressor.option("pure_getters")) return true; return this.expression.has_side_effects(compressor); }); def(AST_Sub, function(compressor){ - if (!compressor.option("clean_getters")) return true; + if (!compressor.option("pure_getters")) return true; return this.expression.has_side_effects(compressor) || this.property.has_side_effects(compressor); }); def(AST_PropAccess, function(compressor){ - return !compressor.option("clean_getters"); + return !compressor.option("pure_getters"); }); def(AST_Seq, function(compressor){ return this.car.has_side_effects(compressor) -- 2.34.1