From 71d9d4fa0eccbebe4a2ab50d17b563f20c4b42e9 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 21 Aug 2015 18:47:54 -0400 Subject: [PATCH] only rewrite exported vars as exports.foo if necessary --- src/Bundle.js | 8 +++--- src/Module.js | 25 +++++++++++++++---- src/Statement.js | 13 ++++++++++ test/form/exported-empty-vars/_config.js | 6 ----- .../form/exported-empty-vars/_expected/amd.js | 8 ------ .../form/exported-empty-vars/_expected/cjs.js | 6 ----- .../form/exported-empty-vars/_expected/es6.js | 9 ------- .../exported-empty-vars/_expected/iife.js | 8 ------ .../form/exported-empty-vars/_expected/umd.js | 12 --------- test/form/exported-empty-vars/bar.js | 6 ----- test/form/exported-empty-vars/foo.js | 2 -- test/form/exported-empty-vars/main.js | 2 -- .../exports-at-end-if-possible/_config.js | 2 +- .../_expected/es6.js | 2 +- test/form/multiple-exports/_expected/amd.js | 7 ++++-- test/form/multiple-exports/_expected/cjs.js | 7 ++++-- test/form/multiple-exports/_expected/iife.js | 7 ++++-- test/form/multiple-exports/_expected/umd.js | 7 ++++-- .../_expected/amd.js | 4 ++- .../_expected/cjs.js | 4 ++- .../_expected/iife.js | 4 ++- .../_expected/umd.js | 4 ++- .../function/assignment-to-exports/_config.js | 3 ++- 23 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 test/form/exported-empty-vars/_config.js delete mode 100644 test/form/exported-empty-vars/_expected/amd.js delete mode 100644 test/form/exported-empty-vars/_expected/cjs.js delete mode 100644 test/form/exported-empty-vars/_expected/es6.js delete mode 100644 test/form/exported-empty-vars/_expected/iife.js delete mode 100644 test/form/exported-empty-vars/_expected/umd.js delete mode 100644 test/form/exported-empty-vars/bar.js delete mode 100644 test/form/exported-empty-vars/foo.js delete mode 100644 test/form/exported-empty-vars/main.js diff --git a/src/Bundle.js b/src/Bundle.js index 0fd7656..aac7790 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -290,13 +290,13 @@ export default class Bundle { // // This doesn't apply if the bundle is exported as ES6! let allBundleExports = blank(); - let isVarDeclaration = blank(); + let isReassignedVarDeclaration = blank(); let varExports = blank(); let getterExports = []; this.orderedModules.forEach( module => { - module.varDeclarations.forEach( name => { - isVarDeclaration[ module.replacements[ name ] || name ] = true; + module.reassignments.forEach( name => { + isReassignedVarDeclaration[ module.replacements[ name ] || name ] = true; }); }); @@ -306,7 +306,7 @@ export default class Bundle { .forEach( name => { const canonicalName = this.traceExport( this.entryModule, name ); - if ( isVarDeclaration[ canonicalName ] ) { + if ( isReassignedVarDeclaration[ canonicalName ] ) { varExports[ name ] = true; // if the same binding is exported multiple ways, we need to diff --git a/src/Module.js b/src/Module.js index 9964ae2..461c20b 100644 --- a/src/Module.js +++ b/src/Module.js @@ -64,7 +64,7 @@ export default class Module { this.replacements = blank(); - this.varDeclarations = []; + this.reassignments = []; this.definitions = blank(); this.definitionPromises = blank(); @@ -202,20 +202,35 @@ export default class Module { this.definitions[ name ] = statement; }); - statement.scope.varDeclarations.forEach( name => { - this.varDeclarations.push( name ); - }); - keys( statement.modifies ).forEach( name => { ( this.modifications[ name ] || ( this.modifications[ name ] = [] ) ).push( statement ); }); }); + // discover variables that are reassigned inside function + // bodies, so we can keep bindings live, e.g. + // + // export var count = 0; + // export function incr () { count += 1 } + let reassigned = blank(); + this.statements.forEach( statement => { + keys( statement.reassigns ).forEach( name => { + reassigned[ name ] = true; + }); + }); + // if names are referenced that are neither defined nor imported // in this module, we assume that they're globals this.statements.forEach( statement => { if ( statement.isReexportDeclaration ) return; + // while we're here, mark reassignments + statement.scope.varDeclarations.forEach( name => { + if ( reassigned[ name ] && !~this.reassignments.indexOf( name ) ) { + this.reassignments.push( name ); + } + }); + keys( statement.dependsOn ).forEach( name => { if ( !this.definitions[ name ] && !this.imports[ name ] ) { this.bundle.assumedGlobals[ name ] = true; diff --git a/src/Statement.js b/src/Statement.js index b68d216..ad66b15 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -30,6 +30,8 @@ export default class Statement { this.dependsOn = blank(); this.stronglyDependsOn = blank(); + this.reassigns = blank(); + this.isIncluded = false; this.isImportDeclaration = node.type === 'ImportDeclaration'; @@ -227,6 +229,17 @@ export default class Statement { this.module.exports.default.isModified = true; } } + + // we track updates/reassignments to variables, to know whether we + // need to rewrite it later from `foo` to `exports.foo` to keep + // bindings live + if ( + depth === 0 && + writeDepth > 0 && + !scope.contains( node.name ) + ) { + this.reassigns[ node.name ] = true; + } } // we only care about writes that happen a) at the top level, diff --git a/test/form/exported-empty-vars/_config.js b/test/form/exported-empty-vars/_config.js deleted file mode 100644 index fa0287c..0000000 --- a/test/form/exported-empty-vars/_config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - description: 'removes empty var declarations that are exported', - options: { - moduleName: 'myBundle' - } -}; diff --git a/test/form/exported-empty-vars/_expected/amd.js b/test/form/exported-empty-vars/_expected/amd.js deleted file mode 100644 index c0f1472..0000000 --- a/test/form/exported-empty-vars/_expected/amd.js +++ /dev/null @@ -1,8 +0,0 @@ -define(['exports'], function (exports) { 'use strict'; - - exports.foo = 42; - - exports.bar = 43; - exports.baz = 44; - -}); diff --git a/test/form/exported-empty-vars/_expected/cjs.js b/test/form/exported-empty-vars/_expected/cjs.js deleted file mode 100644 index 4011bd7..0000000 --- a/test/form/exported-empty-vars/_expected/cjs.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -exports.foo = 42; - -exports.bar = 43; -exports.baz = 44; diff --git a/test/form/exported-empty-vars/_expected/es6.js b/test/form/exported-empty-vars/_expected/es6.js deleted file mode 100644 index 4b76753..0000000 --- a/test/form/exported-empty-vars/_expected/es6.js +++ /dev/null @@ -1,9 +0,0 @@ -var foo; -foo = 42; - -var bar; -var baz; -bar = 43; -baz = 44; - -export { foo, bar, baz }; diff --git a/test/form/exported-empty-vars/_expected/iife.js b/test/form/exported-empty-vars/_expected/iife.js deleted file mode 100644 index 63c56b2..0000000 --- a/test/form/exported-empty-vars/_expected/iife.js +++ /dev/null @@ -1,8 +0,0 @@ -(function (exports) { 'use strict'; - - exports.foo = 42; - - exports.bar = 43; - exports.baz = 44; - -})((this.myBundle = {})); diff --git a/test/form/exported-empty-vars/_expected/umd.js b/test/form/exported-empty-vars/_expected/umd.js deleted file mode 100644 index 9cde4bd..0000000 --- a/test/form/exported-empty-vars/_expected/umd.js +++ /dev/null @@ -1,12 +0,0 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - factory((global.myBundle = {})); -}(this, function (exports) { 'use strict'; - - exports.foo = 42; - - exports.bar = 43; - exports.baz = 44; - -})); diff --git a/test/form/exported-empty-vars/bar.js b/test/form/exported-empty-vars/bar.js deleted file mode 100644 index b8818da..0000000 --- a/test/form/exported-empty-vars/bar.js +++ /dev/null @@ -1,6 +0,0 @@ -var bar, baz; - -bar = 43; -baz = 44; - -export { bar, baz }; diff --git a/test/form/exported-empty-vars/foo.js b/test/form/exported-empty-vars/foo.js deleted file mode 100644 index 2c71d30..0000000 --- a/test/form/exported-empty-vars/foo.js +++ /dev/null @@ -1,2 +0,0 @@ -export var foo; -foo = 42; diff --git a/test/form/exported-empty-vars/main.js b/test/form/exported-empty-vars/main.js deleted file mode 100644 index 21ee721..0000000 --- a/test/form/exported-empty-vars/main.js +++ /dev/null @@ -1,2 +0,0 @@ -export { foo } from './foo'; -export { bar, baz } from './bar'; diff --git a/test/form/exports-at-end-if-possible/_config.js b/test/form/exports-at-end-if-possible/_config.js index 84caf3f..a898bc7 100644 --- a/test/form/exports-at-end-if-possible/_config.js +++ b/test/form/exports-at-end-if-possible/_config.js @@ -3,5 +3,5 @@ module.exports = { options: { moduleName: 'myBundle' }, - solo: true + // solo: true }; diff --git a/test/form/exports-at-end-if-possible/_expected/es6.js b/test/form/exports-at-end-if-possible/_expected/es6.js index 14fc9e9..b42b4e4 100644 --- a/test/form/exports-at-end-if-possible/_expected/es6.js +++ b/test/form/exports-at-end-if-possible/_expected/es6.js @@ -1,4 +1,4 @@ -const FOO = 'foo'; +var FOO = 'foo'; console.log( FOO ); console.log( FOO ); diff --git a/test/form/multiple-exports/_expected/amd.js b/test/form/multiple-exports/_expected/amd.js index 5460f4f..2ebff3b 100644 --- a/test/form/multiple-exports/_expected/amd.js +++ b/test/form/multiple-exports/_expected/amd.js @@ -1,6 +1,9 @@ define(['exports'], function (exports) { 'use strict'; - exports.foo = 1; - exports.bar = 2; + var foo = 1; + var bar = 2; + + exports.foo = foo; + exports.bar = bar; }); diff --git a/test/form/multiple-exports/_expected/cjs.js b/test/form/multiple-exports/_expected/cjs.js index 0bbfe60..1968b8b 100644 --- a/test/form/multiple-exports/_expected/cjs.js +++ b/test/form/multiple-exports/_expected/cjs.js @@ -1,4 +1,7 @@ 'use strict'; -exports.foo = 1; -exports.bar = 2; +var foo = 1; +var bar = 2; + +exports.foo = foo; +exports.bar = bar; diff --git a/test/form/multiple-exports/_expected/iife.js b/test/form/multiple-exports/_expected/iife.js index 09461cb..8ed8290 100644 --- a/test/form/multiple-exports/_expected/iife.js +++ b/test/form/multiple-exports/_expected/iife.js @@ -1,6 +1,9 @@ (function (exports) { 'use strict'; - exports.foo = 1; - exports.bar = 2; + var foo = 1; + var bar = 2; + + exports.foo = foo; + exports.bar = bar; })((this.myBundle = {})); diff --git a/test/form/multiple-exports/_expected/umd.js b/test/form/multiple-exports/_expected/umd.js index 2fd0eb7..687b75c 100644 --- a/test/form/multiple-exports/_expected/umd.js +++ b/test/form/multiple-exports/_expected/umd.js @@ -4,7 +4,10 @@ factory((global.myBundle = {})); }(this, function (exports) { 'use strict'; - exports.foo = 1; - exports.bar = 2; + var foo = 1; + var bar = 2; + + exports.foo = foo; + exports.bar = bar; })); diff --git a/test/form/preserves-comments-after-imports/_expected/amd.js b/test/form/preserves-comments-after-imports/_expected/amd.js index fd4591b..82a0a52 100644 --- a/test/form/preserves-comments-after-imports/_expected/amd.js +++ b/test/form/preserves-comments-after-imports/_expected/amd.js @@ -4,6 +4,8 @@ define(['exports'], function (exports) { 'use strict'; var number = 5; /** A comment for obj */ - exports.obj = { number }; + var obj = { number }; + + exports.obj = obj; }); diff --git a/test/form/preserves-comments-after-imports/_expected/cjs.js b/test/form/preserves-comments-after-imports/_expected/cjs.js index 86e64c1..8b15cd1 100644 --- a/test/form/preserves-comments-after-imports/_expected/cjs.js +++ b/test/form/preserves-comments-after-imports/_expected/cjs.js @@ -4,4 +4,6 @@ var number = 5; /** A comment for obj */ -exports.obj = { number }; +var obj = { number }; + +exports.obj = obj; diff --git a/test/form/preserves-comments-after-imports/_expected/iife.js b/test/form/preserves-comments-after-imports/_expected/iife.js index 02f5255..9da8252 100644 --- a/test/form/preserves-comments-after-imports/_expected/iife.js +++ b/test/form/preserves-comments-after-imports/_expected/iife.js @@ -4,6 +4,8 @@ var number = 5; /** A comment for obj */ - exports.obj = { number }; + var obj = { number }; + + exports.obj = obj; })((this.myBundle = {})); diff --git a/test/form/preserves-comments-after-imports/_expected/umd.js b/test/form/preserves-comments-after-imports/_expected/umd.js index 6993070..96fec25 100644 --- a/test/form/preserves-comments-after-imports/_expected/umd.js +++ b/test/form/preserves-comments-after-imports/_expected/umd.js @@ -8,6 +8,8 @@ var number = 5; /** A comment for obj */ - exports.obj = { number }; + var obj = { number }; + + exports.obj = obj; })); diff --git a/test/function/assignment-to-exports/_config.js b/test/function/assignment-to-exports/_config.js index c958adb..fac0cb3 100644 --- a/test/function/assignment-to-exports/_config.js +++ b/test/function/assignment-to-exports/_config.js @@ -6,5 +6,6 @@ module.exports = { assert.equal( exports.count, 0 ); exports.incr(); assert.equal( exports.count, 1 ); - } + }, + // solo: true };