improved tree shaking for star exports

fixes #3415
This commit is contained in:
Tobias Koppers 2016-12-04 23:16:33 +01:00
parent 99396be94c
commit bfc1359a86
31 changed files with 116 additions and 36 deletions

View File

@ -120,13 +120,17 @@ function MainTemplate(outputOptions) {
buf.push("// define getter function for harmory exports");
buf.push(this.requireFn + ".d = function(exports, name, getter) {");
buf.push(this.indent([
"Object.defineProperty(exports, name, {",
"if(!" + this.requireFn + ".o(exports, name)) {",
this.indent([
"configurable: false,",
"enumerable: true,",
"get: getter"
"Object.defineProperty(exports, name, {",
this.indent([
"configurable: false,",
"enumerable: true,",
"get: getter"
]),
"});"
]),
"});"
"}"
]));
buf.push("};");

View File

@ -30,7 +30,7 @@ HarmonyExportImportedSpecifierDependency.prototype.getReference = function() {
// export *
if(Array.isArray(this.originModule.usedExports)) {
// reexport * with known used exports
var activeExports = HarmonyModulesHelpers.getActiveExports(this.originModule);
var activeExports = HarmonyModulesHelpers.getActiveExports(this.originModule, this);
if(Array.isArray(m.providedExports)) {
return {
module: m,
@ -108,6 +108,14 @@ HarmonyExportImportedSpecifierDependency.prototype.getExports = function() {
};
HarmonyExportImportedSpecifierDependency.prototype.describeHarmonyExport = function() {
var importedModule = this.importDependency.module;
if(!this.name && importedModule && Array.isArray(importedModule.providedExports)) {
// for a star export and when we know which exports are provided, we can tell so
return {
exportedName: importedModule.providedExports,
precedence: 3
}
}
return {
exportedName: this.name,
precedence: this.name ? 2 : 3
@ -149,7 +157,7 @@ HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep
} else if(dep.name) { // we want to reexport the module object as named export
content = "/* harmony reexport (module object) */ " + getReexportStatement(JSON.stringify(used), "");
} else if(Array.isArray(dep.originModule.usedExports)) { // we know which exports are used
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule);
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule, dep);
items = dep.originModule.usedExports.map(function(id) {
if(id === "default") return;
if(activeExports.indexOf(id) >= 0) return;
@ -164,7 +172,7 @@ HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep
}).join("");
} else content = "/* unused harmony namespace reexport */\n";
} else if(dep.originModule.usedExports && importedModule && Array.isArray(importedModule.providedExports)) { // not sure which exports are used, but we know which are provided
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule);
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule, dep);
items = importedModule.providedExports.map(function(id) {
if(id === "default") return;
if(activeExports.indexOf(id) >= 0) return;
@ -178,7 +186,7 @@ HarmonyExportImportedSpecifierDependency.Template.prototype.apply = function(dep
}).join("");
} else content = "/* empty harmony namespace reexport */\n";
} else if(dep.originModule.usedExports) { // not sure which exports are used and provided
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule);
activeExports = HarmonyModulesHelpers.getActiveExports(dep.originModule, dep);
content = "/* harmony namespace reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in " + name + ") ";
// Filter out exports which are defined by other exports

View File

@ -55,16 +55,26 @@ HarmonyModulesHelpers.isActive = function(module, depInQuestion) {
// get a list of named exports defined in a module
// doesn't include * reexports.
HarmonyModulesHelpers.getActiveExports = function(module) {
if(module.activeExports)
return module.activeExports;
return module.dependencies.reduce(function(arr, dep) {
HarmonyModulesHelpers.getActiveExports = function(module, currentDependency) {
var desc = currentDependency && currentDependency.describeHarmonyExport();
var currentIndex = currentDependency ? module.dependencies.indexOf(currentDependency) : -1;
return module.dependencies.map(function(dep, idx) {
return {
dep: dep,
idx: idx
}
}).reduce(function(arr, data) {
var dep = data.dep;
if(!dep.describeHarmonyExport) return arr;
var d = dep.describeHarmonyExport();
if(!d) return arr;
var name = d.exportedName;
if(!name || arr.indexOf(name) >= 0) return arr;
arr.push(name);
if(!desc || (d.precedence < desc.precedence) || (d.precedence === desc.precedence && data.idx < currentIndex)) {
var names = [].concat(d.exportedName);
names.forEach(function(name) {
if(name && arr.indexOf(name) < 0)
arr.push(name);
});
}
return arr;
}, [])
}, []);
};

View File

@ -0,0 +1,2 @@
export var x = "1";
export * from "./a";

View File

@ -0,0 +1,2 @@
export * from "./a";
export var x = "1";

View File

@ -0,0 +1,2 @@
export * from "./a";
export * from "./b";

View File

@ -0,0 +1,2 @@
export * from "./b";
export * from "./a";

View File

@ -0,0 +1,2 @@
export * from "./c";
export * from "./d";

View File

@ -0,0 +1,4 @@
export * from "./a";
export * from "./b";
export * from "./c";
export * from "./d";

View File

@ -0,0 +1,4 @@
export * from "./d";
export * from "./b";
export * from "./c";
export * from "./a";

View File

@ -0,0 +1 @@
export var x = "a";

View File

@ -0,0 +1 @@
export var x = "b";

View File

@ -0,0 +1 @@
exports.x = "c";

View File

@ -0,0 +1 @@
exports.x = "d";

View File

@ -0,0 +1,35 @@
import { x as x1 } from "./1?a";
import { x as x2 } from "./2?a";
import { x as x3 } from "./3?a";
import { x as x4 } from "./4?a";
import { x as x5 } from "./5?a";
import { x as x6 } from "./6?a";
import { x as x7 } from "./7?a";
var y1 = require("./1?b").x;
var y2 = require("./2?b").x;
var y3 = require("./3?b").x;
var y4 = require("./4?b").x;
var y5 = require("./5?b").x;
var y6 = require("./6?b").x;
var y7 = require("./7?b").x;
it("should not overwrite when using star export (known exports)", function() {
x1.should.be.eql("1");
x2.should.be.eql("1");
x3.should.be.eql("a");
x4.should.be.eql("b");
x5.should.be.eql("c");
x6.should.be.eql("a");
x7.should.be.eql("d");
});
it("should not overwrite when using star export (unknown exports)", function() {
y1.should.be.eql("1");
y2.should.be.eql("1");
y3.should.be.eql("a");
y4.should.be.eql("b");
y5.should.be.eql("c");
y6.should.be.eql("a");
y7.should.be.eql("d");
});

View File

@ -0,0 +1 @@
export * from "./a";

View File

@ -1,7 +1,7 @@
Hash: 8e46421d7f7a7d266a00
Time: Xms
Asset Size Chunks Chunk Names
48c8b1dae03a37363ec8.js 4.17 kB 1 [emitted]
48c8b1dae03a37363ec8.js 4.24 kB 1 [emitted]
2fa7af5012a3d8b778dd.js 2.22 kB 2 [emitted]
a5b577236621262c2bcf.js 1.93 kB 3 [emitted]
88d78642a86768757078.js 977 bytes 4 [emitted]

View File

@ -6,7 +6,7 @@ Time: Xms
5ae9e18455b866684bd0.js 1.94 kB 2 [emitted]
e91ec4902ca3057b42bb.js 1.93 kB 3 [emitted]
0947f0875d56ab0bfe02.js 977 bytes 4 [emitted]
6335d9dcc7fa048743b7.js 7.13 kB 6 [emitted] main
6335d9dcc7fa048743b7.js 7.2 kB 6 [emitted] main
cf500be0e585f01d2ccb.js 983 bytes 9 [emitted]
a7bfb642a544b4302cc4.js 975 bytes 11 [emitted]
Entrypoint main = 6335d9dcc7fa048743b7.js

View File

@ -4,7 +4,7 @@ Time: Xms
0.bundle.js 227 bytes 0 [emitted]
1.bundle.js 106 bytes 1 [emitted]
2.bundle.js 200 bytes 2 [emitted]
bundle.js 5.77 kB 3 [emitted] main
bundle.js 5.84 kB 3 [emitted] main
chunk {0} 0.bundle.js 54 bytes {3} [rendered]
> [5] (webpack)/test/statsCases/chunks/index.js 3:0-16
[2] (webpack)/test/statsCases/chunks/c.js 54 bytes {0} [built]

View File

@ -1,6 +1,6 @@
Hash: 6c781fe6bf412ba6435b
Time: Xms
Asset Size Chunks Chunk Names
main.js 2.43 kB 0 [emitted] main
main.js 2.51 kB 0 [emitted] main
chunk {0} main.js (main) 0 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/color-disabled/index.js 0 bytes {0} [built]

View File

@ -1,6 +1,6 @@
Hash: <CLR=BOLD>6c781fe6bf412ba6435b</CLR>
Time: <CLR=BOLD>X</CLR>ms
<CLR=BOLD>Asset</CLR> <CLR=BOLD>Size</CLR> <CLR=BOLD>Chunks</CLR> <CLR=39,BOLD><CLR=22> <CLR=BOLD>Chunk Names</CLR>
<CLR=32>main.js</CLR> 2.43 kB <CLR=BOLD>0</CLR> <CLR=32>[emitted]</CLR> main
<CLR=32>main.js</CLR> 2.51 kB <CLR=BOLD>0</CLR> <CLR=32>[emitted]</CLR> main
chunk {<CLR=33>0</CLR>} <CLR=32>main.js</CLR> (main) 0 bytes<CLR=33> [entry]</CLR><CLR=32> [rendered]</CLR>
[0] <CLR=BOLD>(webpack)/test/statsCases/color-enabled-custom/index.js</CLR> 0 bytes {<CLR=33>0</CLR>}<CLR=32> [built]</CLR>

View File

@ -1,6 +1,6 @@
Hash: <CLR=BOLD>6c781fe6bf412ba6435b</CLR>
Time: <CLR=BOLD>X</CLR>ms
<CLR=BOLD>Asset</CLR> <CLR=BOLD>Size</CLR> <CLR=BOLD>Chunks</CLR> <CLR=39,BOLD><CLR=22> <CLR=BOLD>Chunk Names</CLR>
<CLR=32,BOLD>main.js</CLR> 2.43 kB <CLR=BOLD>0</CLR> <CLR=32,BOLD>[emitted]</CLR> main
<CLR=32,BOLD>main.js</CLR> 2.51 kB <CLR=BOLD>0</CLR> <CLR=32,BOLD>[emitted]</CLR> main
chunk {<CLR=33,BOLD>0</CLR>} <CLR=32,BOLD>main.js</CLR> (main) 0 bytes<CLR=33,BOLD> [entry]</CLR><CLR=32,BOLD> [rendered]</CLR>
[0] <CLR=BOLD>(webpack)/test/statsCases/color-enabled/index.js</CLR> 0 bytes {<CLR=33,BOLD>0</CLR>}<CLR=32,BOLD> [built]</CLR>

View File

@ -3,13 +3,13 @@ Child
Hash: 052d0451a89cb963e4d3
Time: Xms
Asset Size Chunks Chunk Names
main.js 2.48 kB 0 [emitted] main
main.js 2.55 kB 0 [emitted] main
chunk {0} main.js (main) 24 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/define-plugin/index.js 24 bytes {0} [built]
Child
Hash: eb3ff8e5a88b9234d04f
Time: Xms
Asset Size Chunks Chunk Names
main.js 2.48 kB 0 [emitted] main
main.js 2.55 kB 0 [emitted] main
chunk {0} main.js (main) 24 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/define-plugin/index.js 24 bytes {0} [built]

View File

@ -1,7 +1,7 @@
Hash: affacd3db222d3fcb700
Time: Xms
Asset Size Chunks Chunk Names
bundle.js 2.69 kB 0 [emitted] main
bundle.js 2.77 kB 0 [emitted] main
chunk {0} bundle.js (main) 132 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/exclude-with-loader/a.txt 43 bytes {0} [built]
[2] (webpack)/test/statsCases/exclude-with-loader/index.js 46 bytes {0} [built]

View File

@ -1,7 +1,7 @@
Hash: 5957a4911072fb217ca1
Time: Xms
Asset Size Chunks Chunk Names
main.js 2.57 kB 0 [emitted] main
main.js 2.64 kB 0 [emitted] main
chunk {0} main.js (main) 59 bytes [entry] [rendered]
[0] external "test" 42 bytes {0} [not cacheable]
[1] (webpack)/test/statsCases/external/index.js 17 bytes {0} [built]

View File

@ -8,7 +8,7 @@ Time: Xms
4.js 136 bytes 4, 6 [emitted] chunk
5.js 293 bytes 5, 3 [emitted] cir2 from cir1
6.js 78 bytes 6 [emitted] ac in ab
main.js 6.37 kB 7 [emitted] main
main.js 6.45 kB 7 [emitted] main
chunk {0} 0.js (cir1) 81 bytes {7} {5} {3} [rendered]
> duplicate cir1 from cir2 [3] (webpack)/test/statsCases/optimize-chunks/circular2.js 1:0-79
> duplicate cir1 [8] (webpack)/test/statsCases/optimize-chunks/index.js 13:0-54

View File

@ -4,7 +4,7 @@ Time: Xms
0.js 227 bytes 0 [emitted]
1.js 106 bytes 1 [emitted]
2.js 200 bytes 2 [emitted]
main.js 5.76 kB 3 [emitted] main
main.js 5.83 kB 3 [emitted] main
Entrypoint main = main.js
chunk {0} 0.js 54 bytes {3} [rendered]
[2] (webpack)/test/statsCases/preset-verbose/c.js 54 bytes {0} [built]

View File

@ -3,7 +3,7 @@ Child
Hash: 9ff2cfa8882f273c8c6d
Time: Xms
Asset Size Chunks Chunk Names
f49aa1e6c5ada5da859b.js 2.57 kB 0 [emitted] main
f49aa1e6c5ada5da859b.js 2.65 kB 0 [emitted] main
c815cf440254d4f3bba4e7041db00a28.css 26 bytes 0 [emitted] main
chunk {0} f49aa1e6c5ada5da859b.js, c815cf440254d4f3bba4e7041db00a28.css (main) 64 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/separate-css-bundle/a/file.css 41 bytes {0} [built]
@ -16,7 +16,7 @@ Child
Hash: 9ff2cfa8882f273c8c6d
Time: Xms
Asset Size Chunks Chunk Names
f49aa1e6c5ada5da859b.js 2.57 kB 0 [emitted] main
f49aa1e6c5ada5da859b.js 2.65 kB 0 [emitted] main
a3f385680aef7a9bb2a517699532cc34.css 28 bytes 0 [emitted] main
chunk {0} f49aa1e6c5ada5da859b.js, a3f385680aef7a9bb2a517699532cc34.css (main) 64 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/separate-css-bundle/b/file.css 41 bytes {0} [built]

View File

@ -1,7 +1,7 @@
Hash: 0bd4f09244f0e8c60354
Time: Xms
Asset Size Chunks Chunk Names
bundle.js 2.43 kB 0 [emitted] main
bundle.js 2.51 kB 0 [emitted] main
chunk {0} bundle.js (main) 0 bytes [entry] [rendered]
> main [0] (webpack)/test/statsCases/simple-more-info/index.js
[0] (webpack)/test/statsCases/simple-more-info/index.js 0 bytes {0} [built]

View File

@ -1,6 +1,6 @@
Hash: 0bd4f09244f0e8c60354
Time: Xms
Asset Size Chunks Chunk Names
bundle.js 2.43 kB 0 [emitted] main
bundle.js 2.51 kB 0 [emitted] main
chunk {0} bundle.js (main) 0 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/simple/index.js 0 bytes {0} [built]

View File

@ -1,7 +1,7 @@
Hash: 8bac53cc0c37d71baf6b
Hash: 9e57dbeb6deda98eb9bf
Time: Xms
Asset Size Chunks Chunk Names
bundle.js 7.22 kB 0 [emitted] main
bundle.js 7.08 kB 0 [emitted] main
chunk {0} bundle.js (main) 588 bytes [entry] [rendered]
[0] (webpack)/test/statsCases/tree-shaking/a.js 13 bytes {0} [built]
[exports: a]
@ -10,7 +10,7 @@ chunk {0} bundle.js (main) 588 bytes [entry] [rendered]
[exports: b]
[only some exports used: ]
[2] (webpack)/test/statsCases/tree-shaking/unknown.js 0 bytes {0} [built]
[only some exports used: a, c]
[only some exports used: c]
[3] (webpack)/test/statsCases/tree-shaking/edge.js 45 bytes {0} [built]
[only some exports used: y]
[4] (webpack)/test/statsCases/tree-shaking/reexport-known.js 49 bytes {0} [built]