From 66288dcba93347f55e1d2d72865875ad39f3d453 Mon Sep 17 00:00:00 2001 From: Boopathi Rajaa Date: Fri, 11 Aug 2017 23:21:15 +0200 Subject: [PATCH 1/3] Make tdz optional in helper evaluate For common case, detecting tdz isn't required. Make it optional. --- .../babel-helper-evaluate-path/src/index.js | 12 ++++++-- packages/babel-minify/src/cli.js | 13 ++++++-- .../babel-plugin-minify-builtins/src/index.js | 9 +++--- .../src/index.js | 4 +-- .../__tests__/dead-code-elimination-test.js | 30 +++++++++++++++---- .../src/index.js | 20 +++++++------ packages/babel-preset-minify/src/index.js | 3 +- 7 files changed, 64 insertions(+), 27 deletions(-) diff --git a/packages/babel-helper-evaluate-path/src/index.js b/packages/babel-helper-evaluate-path/src/index.js index 4e71e8295..3ed6d322a 100644 --- a/packages/babel-helper-evaluate-path/src/index.js +++ b/packages/babel-helper-evaluate-path/src/index.js @@ -1,6 +1,10 @@ "use strict"; -module.exports = function evaluate(path) { +module.exports = function evaluate(path, { tdz = false } = {}) { + if (!tdz) { + return baseEvaluate(path); + } + if (path.isReferencedIdentifier()) { return evaluateIdentifier(path); } @@ -32,6 +36,10 @@ module.exports = function evaluate(path) { return state; } + return baseEvaluate(path); +}; + +function baseEvaluate(path) { try { return path.evaluate(); } catch (e) { @@ -40,7 +48,7 @@ module.exports = function evaluate(path) { error: e }; } -}; +} // Original Source: // https://github.com/babel/babel/blob/master/packages/babel-traverse/src/path/evaluation.js diff --git a/packages/babel-minify/src/cli.js b/packages/babel-minify/src/cli.js index 8274d0dfa..cdc4b5e59 100644 --- a/packages/babel-minify/src/cli.js +++ b/packages/babel-minify/src/cli.js @@ -28,7 +28,7 @@ const plugins = [ "undefinedToVoid" ]; -const proxies = ["keepFnName", "keepClassName"]; +const proxies = ["keepFnName", "keepClassName", "tdz"]; const dceBooleanOpts = [ "deadcode.keepFnName", @@ -72,9 +72,11 @@ function printHelpInfo({ exitCode = 0 } = {}) { const msg = ` Usage: minify index.js [options] - Options: + IO Options: --out-file, -o Output to a specific file --out-dir, -d Output to a specific directory + + Transform Options: --mangle Context and scope aware variable renaming --simplify Simplifies code for minification by reducing statements into expressions @@ -102,7 +104,12 @@ function printHelpInfo({ exitCode = 0 } = {}) { to be the same --typeConstructors Minify constructors to equivalent version --undefinedToVoid Transforms undefined into void 0 - --version, -V Prints the current version number + + Other Options: + --keepFnName Preserve Function Name (useful for code depending on fn.name) + --keepClassName Preserve Class Name (useful for code depending on c.name) + --keepFnArgs Don't remove unused fn arguments (useful for code depending on fn.length) + --tdz Detect usages of variables in the Temporal Dead Zone Nested Options: To use nested options (plugin specfic options) simply use the pattern diff --git a/packages/babel-plugin-minify-builtins/src/index.js b/packages/babel-plugin-minify-builtins/src/index.js index 5f1119e01..53b46bf64 100644 --- a/packages/babel-plugin-minify-builtins/src/index.js +++ b/packages/babel-plugin-minify-builtins/src/index.js @@ -8,8 +8,9 @@ const INVALID_METHODS = ["random"]; module.exports = function({ types: t }) { class BuiltInReplacer { - constructor(program) { + constructor(program, { tdz }) { this.program = program; + this.tdz = tdz; // map; this.pathsToUpdate = new Map(); } @@ -48,7 +49,7 @@ module.exports = function({ types: t }) { // computed property should be not optimized // Math[max]() -> Math.max() if (!isComputed(callee) && isBuiltin(callee)) { - const result = evaluate(path); + const result = evaluate(path, { tdz: context.tdz }); // deopt when we have side effecty evaluate-able arguments // Math.max(foo(), 1) --> untouched // Math.floor(1) --> 1 @@ -96,8 +97,8 @@ module.exports = function({ types: t }) { return { name: "minify-builtins", visitor: { - Program(path) { - const builtInReplacer = new BuiltInReplacer(path); + Program(path, { opts: { tdz = false } = {} }) { + const builtInReplacer = new BuiltInReplacer(path, { tdz }); builtInReplacer.run(); } } diff --git a/packages/babel-plugin-minify-constant-folding/src/index.js b/packages/babel-plugin-minify-constant-folding/src/index.js index 5e591a4f2..729919d01 100644 --- a/packages/babel-plugin-minify-constant-folding/src/index.js +++ b/packages/babel-plugin-minify-constant-folding/src/index.js @@ -95,7 +95,7 @@ module.exports = babel => { }, // TODO: look into evaluating binding too (could result in more code, but gzip?) - Expression(path) { + Expression(path, { opts: { tdz = false } = {} }) { const { node } = path; if (node[seen]) { @@ -143,7 +143,7 @@ module.exports = babel => { return; } - const res = evaluate(path); + const res = evaluate(path, { tdz }); if (res.confident) { // Avoid fractions because they can be longer than the original expression. // There is also issues with number percision? diff --git a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js index aed518ebc..045305e7d 100644 --- a/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js +++ b/packages/babel-plugin-minify-dead-code-elimination/__tests__/dead-code-elimination-test.js @@ -525,7 +525,10 @@ describe("dce-plugin", () => { if (a) return; x(); } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); thePlugin( @@ -536,7 +539,10 @@ describe("dce-plugin", () => { if (a) return 1; x(); } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); thePlugin( @@ -552,7 +558,10 @@ describe("dce-plugin", () => { y(); } } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); thePlugin( @@ -2452,7 +2461,10 @@ describe("dce-plugin", () => { if (v) var w = 10; if (w) console.log("hello", v); } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); thePlugin.skip( @@ -2462,7 +2474,10 @@ describe("dce-plugin", () => { bar(a); // Should be a ReferenceError let a = 1; } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); thePlugin( @@ -2483,6 +2498,9 @@ describe("dce-plugin", () => { if (a) console.log(a); }; } - ` + `, + { + plugins: [[deadcode, { tdz: true }]] + } ); }); diff --git a/packages/babel-plugin-minify-dead-code-elimination/src/index.js b/packages/babel-plugin-minify-dead-code-elimination/src/index.js index 2557e61f2..e15fae757 100644 --- a/packages/babel-plugin-minify-dead-code-elimination/src/index.js +++ b/packages/babel-plugin-minify-dead-code-elimination/src/index.js @@ -509,7 +509,7 @@ module.exports = ({ types: t, traverse }) => { SwitchStatement: { exit(path) { - const evaluated = evaluate(path.get("discriminant")); + const evaluated = evaluate(path.get("discriminant"), { tdz: this.tdz }); if (!evaluated.confident) return; @@ -528,7 +528,7 @@ module.exports = ({ types: t, traverse }) => { continue; } - const testResult = evaluate(test); + const testResult = evaluate(test, { tdz: this.tdz }); // if we are not able to deternine a test during // compile time, we terminate immediately @@ -614,7 +614,7 @@ module.exports = ({ types: t, traverse }) => { WhileStatement(path) { const test = path.get("test"); - const result = evaluate(test); + const result = evaluate(test, { tdz: this.tdz }); if (result.confident && test.isPure() && !result.value) { path.remove(); } @@ -624,7 +624,7 @@ module.exports = ({ types: t, traverse }) => { const test = path.get("test"); if (!test.isPure()) return; - const result = evaluate(test); + const result = evaluate(test, { tdz: this.tdz }); if (result.confident) { if (result.value) { test.remove(); @@ -636,7 +636,7 @@ module.exports = ({ types: t, traverse }) => { DoWhileStatement(path) { const test = path.get("test"); - const result = evaluate(test); + const result = evaluate(test, { tdz: this.tdz }); if (result.confident && test.isPure() && !result.value) { const body = path.get("body"); @@ -767,12 +767,12 @@ module.exports = ({ types: t, traverse }) => { } }, IfStatement: { - exit(path) { + exit(path, { opts: { tdz = false } = {} }) { const consequent = path.get("consequent"); const alternate = path.get("alternate"); const test = path.get("test"); - const evalResult = evaluate(test); + const evalResult = evaluate(test, { tdz }); const isPure = test.isPure(); const replacements = []; @@ -864,7 +864,8 @@ module.exports = ({ types: t, traverse }) => { optimizeRawSize = false, keepFnName = false, keepClassName = false, - keepFnArgs = false + keepFnArgs = false, + tdz = false } = {} } = {} ) { @@ -879,7 +880,8 @@ module.exports = ({ types: t, traverse }) => { optimizeRawSize, keepFnName, keepClassName, - keepFnArgs + keepFnArgs, + tdz }); } } diff --git a/packages/babel-preset-minify/src/index.js b/packages/babel-preset-minify/src/index.js index 3504e676b..f6d5963f3 100644 --- a/packages/babel-preset-minify/src/index.js +++ b/packages/babel-preset-minify/src/index.js @@ -33,7 +33,8 @@ const PLUGINS = [ const PROXIES = { keepFnName: ["mangle", "deadcode"], - keepClassName: ["mangle", "deadcode"] + keepClassName: ["mangle", "deadcode"], + tdz: ["builtIns", "evaluate", "deadcode"] }; module.exports = preset; From 0842783f62961f783323a029ef218fedc7f8a120 Mon Sep 17 00:00:00 2001 From: Boopathi Rajaa Date: Sat, 12 Aug 2017 00:25:07 +0200 Subject: [PATCH 2/3] Update README --- packages/babel-preset-minify/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/babel-preset-minify/README.md b/packages/babel-preset-minify/README.md index c5cd9a616..94eb91f0a 100644 --- a/packages/babel-preset-minify/README.md +++ b/packages/babel-preset-minify/README.md @@ -100,6 +100,7 @@ OptionName | Plugins ---------- | ------- keepFnName | Passed to [mangle][mangle] & [deadcode][deadcode] keepClassName | Passed to [mangle][mangle] & [deadcode][deadcode] +tdz | Passed to [builtIns][builtIns], [evaluate][evaluate] & [deadcode][deadcode] **Examples** From 0c2d69dc0f8f778433c85461f66cb7894ae9e11f Mon Sep 17 00:00:00 2001 From: Boopathi Rajaa Date: Sat, 12 Aug 2017 00:43:59 +0200 Subject: [PATCH 3/3] Update READMEs --- packages/babel-plugin-minify-builtins/README.md | 4 ++++ packages/babel-plugin-minify-constant-folding/README.md | 4 ++++ packages/babel-plugin-minify-dead-code-elimination/README.md | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/babel-plugin-minify-builtins/README.md b/packages/babel-plugin-minify-builtins/README.md index 2e23c7e0c..9ccbf5a42 100644 --- a/packages/babel-plugin-minify-builtins/README.md +++ b/packages/babel-plugin-minify-builtins/README.md @@ -49,3 +49,7 @@ require("babel-core").transform("code", { plugins: ["minify-builtins"] }); ``` + +## Options + ++ `tdz` - Account for TDZ (Temporal Dead Zone) diff --git a/packages/babel-plugin-minify-constant-folding/README.md b/packages/babel-plugin-minify-constant-folding/README.md index 6e4eeb2dd..555be1be3 100644 --- a/packages/babel-plugin-minify-constant-folding/README.md +++ b/packages/babel-plugin-minify-constant-folding/README.md @@ -84,3 +84,7 @@ require("babel-core").transform("code", { plugins: ["minify-constant-folding"] }); ``` + +## Options + ++ `tdz` - Account for TDZ (Temporal Dead Zone) diff --git a/packages/babel-plugin-minify-dead-code-elimination/README.md b/packages/babel-plugin-minify-dead-code-elimination/README.md index 63a52b93b..19183bb5c 100644 --- a/packages/babel-plugin-minify-dead-code-elimination/README.md +++ b/packages/babel-plugin-minify-dead-code-elimination/README.md @@ -70,4 +70,5 @@ require("babel-core").transform("code", { + `keepFnName` - prevent plugin from removing function name. Useful for code depending on `fn.name` + `keepFnArgs` - prevent plugin from removing function args. Useful for code depending on `fn.length` -+ `keepClassName` - prevent mangler from altering class names. ++ `keepClassName` - prevent plugin from removing class name. Useful for code depending on `cls.name` ++ `tdz` - Account for TDZ (Temporal Dead Zone)