Skip to content

Commit a867825

Browse files
committed
new algorithm for removing modules from parent chunks
webpack#1905
1 parent 13f8b69 commit a867825

12 files changed

Lines changed: 164 additions & 17 deletions

File tree

lib/optimize/RemoveParentModulesPlugin.js

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,58 @@
22
MIT License http://www.opensource.org/licenses/mit-license.php
33
Author Tobias Koppers @sokra
44
*/
5-
function hasModule(chunk, module, checkedChunks) {
6-
if(chunk.modules.indexOf(module) >= 0) return [chunk];
7-
if(chunk.entry) return false;
8-
return allHaveModule(chunk.parents.filter(function(c) {
9-
return checkedChunks.indexOf(c) < 0;
10-
}), module, checkedChunks);
5+
function listToSet(list, chunk) {
6+
var set = {};
7+
list.forEach(function(module) {
8+
set[module.debugId] = {
9+
module: module,
10+
chunks: [chunk]
11+
};
12+
});
13+
return set;
14+
}
15+
16+
function mergeSets(a, b) {
17+
var newSet = {};
18+
Object.keys(a).forEach(function(key) {
19+
var item = a[key];
20+
newSet[key] = {
21+
module: item.module,
22+
chunks: item.chunks
23+
};
24+
});
25+
Object.keys(b).forEach(function(key) {
26+
var item = b[key];
27+
newSet[key] = {
28+
module: item.module,
29+
chunks: item.chunks
30+
};
31+
});
32+
return newSet;
33+
}
34+
35+
function intersectSets(a, b) {
36+
var newSet = {};
37+
Object.keys(a).forEach(function(key) {
38+
var aItem = a[key];
39+
var bItem = b[key];
40+
if(bItem) {
41+
newSet[key] = {
42+
module: aItem.module,
43+
chunks: aItem.chunks.concat(bItem.chunks)
44+
};
45+
}
46+
});
47+
return newSet;
1148
}
1249

13-
function allHaveModule(someChunks, module, checkedChunks) {
14-
if(!checkedChunks) checkedChunks = [];
15-
var chunks = [];
16-
for(var i = 0; i < someChunks.length; i++) {
17-
checkedChunks.push(someChunks[i]);
18-
var subChunks = hasModule(someChunks[i], module, checkedChunks);
19-
if(!subChunks) return false;
20-
addToSet(chunks, subChunks);
21-
}
22-
return chunks;
50+
function intersectAll(map) {
51+
var keys = Object.keys(map);
52+
if(keys.length === 0)
53+
return null;
54+
return keys.map(function(key) {
55+
return map[key];
56+
}).reduce(intersectSets);
2357
}
2458

2559
function addToSet(set, items) {
@@ -29,16 +63,62 @@ function addToSet(set, items) {
2963
});
3064
}
3165

66+
function toStr(set) {
67+
return Object.keys(set).map(function(key) {
68+
return set[key].module.request.substr(-12);
69+
}).join(", ");
70+
}
71+
3272
function RemoveParentModulesPlugin() {}
3373
module.exports = RemoveParentModulesPlugin;
3474

3575
RemoveParentModulesPlugin.prototype.apply = function(compiler) {
3676
compiler.plugin("compilation", function(compilation) {
3777
compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], function(chunks) {
78+
var todo = chunks.slice().reverse();
79+
todo.forEach(function(chunk, idx) {
80+
chunk._RemoveParentModulesPlugin_processed = false;
81+
chunk._RemoveParentModulesPlugin_availableModulesByChunk = {};
82+
chunk._RemoveParentModulesPlugin_index = idx;
83+
})
84+
for(var i = 0; i < todo.length; i++) {
85+
var chunk = todo[i];
86+
var index = chunk._RemoveParentModulesPlugin_index;
87+
var availableModules = chunk._RemoveParentModulesPlugin_availableModules = intersectAll(chunk._RemoveParentModulesPlugin_availableModulesByChunk);
88+
if(chunk.chunks.length === 0) {
89+
chunk._RemoveParentModulesPlugin_processed = true;
90+
continue;
91+
}
92+
var set = listToSet(chunk.modules);
93+
if(availableModules)
94+
set = mergeSets(set, availableModules);
95+
chunk.chunks.forEach(function(child) {
96+
var availableModules = child._RemoveParentModulesPlugin_availableModulesByChunk[index];
97+
child._RemoveParentModulesPlugin_availableModulesByChunk[index] = set;
98+
if(!availableModules || Object.keys(availableModules).length !== Object.keys(set).length) {
99+
if(child._RemoveParentModulesPlugin_processed) {
100+
todo.push(child);
101+
child._RemoveParentModulesPlugin_processed = false;
102+
}
103+
}
104+
});
105+
chunk._RemoveParentModulesPlugin_processed = true;
106+
}
38107
chunks.forEach(function(chunk) {
108+
var availableModules = chunk._RemoveParentModulesPlugin_availableModules;
109+
delete chunk._RemoveParentModulesPlugin_availableModulesByChunk;
110+
delete chunk._RemoveParentModulesPlugin_availableModules;
111+
delete chunk._RemoveParentModulesPlugin_processed;
112+
delete chunk._RemoveParentModulesPlugin_index;
113+
if(!availableModules) return;
39114
chunk.modules.slice().forEach(function(module) {
40115
if(chunk.entry) return;
41-
var parentChunksWithModule = allHaveModule(chunk.parents, module);
116+
var info = availableModules[module.debugId];
117+
if(!info) return;
118+
var parentChunksWithModule = info.chunks;
119+
parentChunksWithModule = parentChunksWithModule.filter(function(chunk, idx) {
120+
return parentChunksWithModule.indexOf(chunk) === idx;
121+
});
42122
if(parentChunksWithModule) {
43123
module.rewriteChunkInReasons(chunk, parentChunksWithModule);
44124
chunk.removeModule(module);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require.ensure(["./circular2", "./modules/e"], function() {}, "cir2 from cir1");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require.ensure(["./circular1", "./modules/f"], function() {}, "cir1 from cir2");
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Hash: e3dc693bc52a75b4a39b
2+
Time: Xms
3+
Asset Size Chunks Chunk Names
4+
0.js 243 bytes 0 [emitted] cir1
5+
1.js 215 bytes 1, 2 [emitted] abd
6+
2.js 131 bytes 2 [emitted] ab
7+
main.js 5.1 kB 3 [emitted] main
8+
4.js 258 bytes 4 [emitted] cir2
9+
5.js 138 bytes 5, 7 [emitted] chunk
10+
6.js 317 bytes 6, 4 [emitted] cir2 from cir1
11+
7.js 79 bytes 7 [emitted] ac in ab
12+
chunk {0} 0.js (cir1) 81 bytes {3} {6} {4} [rendered]
13+
> cir1 [7] (webpack)/test/statsCases/optimize-chunks/index.js 13:0-54
14+
> duplicate cir1 from cir2 [3] (webpack)/test/statsCases/optimize-chunks/circular2.js 1:0-79
15+
[2] (webpack)/test/statsCases/optimize-chunks/circular1.js 81 bytes {0} [built]
16+
chunk {1} 1.js (abd) 0 bytes {3} [rendered]
17+
> abd [7] (webpack)/test/statsCases/optimize-chunks/index.js 8:0-11:9
18+
[0] (webpack)/test/statsCases/optimize-chunks/modules/a.js 0 bytes {1} {2} [built]
19+
[1] (webpack)/test/statsCases/optimize-chunks/modules/b.js 0 bytes {1} {2} [built]
20+
[5] (webpack)/test/statsCases/optimize-chunks/modules/d.js 0 bytes {1} {5} [built]
21+
chunk {2} 2.js (ab) 0 bytes {3} [rendered]
22+
> ab [7] (webpack)/test/statsCases/optimize-chunks/index.js 1:0-6:8
23+
[0] (webpack)/test/statsCases/optimize-chunks/modules/a.js 0 bytes {1} {2} [built]
24+
[1] (webpack)/test/statsCases/optimize-chunks/modules/b.js 0 bytes {1} {2} [built]
25+
chunk {3} main.js (main) 523 bytes [rendered]
26+
> main [7] (webpack)/test/statsCases/optimize-chunks/index.js
27+
[6] (webpack)/test/statsCases/optimize-chunks/modules/f.js 0 bytes {3} [built]
28+
[7] (webpack)/test/statsCases/optimize-chunks/index.js 523 bytes {3} [built]
29+
chunk {4} 4.js (cir2) 81 bytes {3} [rendered]
30+
> cir2 [7] (webpack)/test/statsCases/optimize-chunks/index.js 14:0-54
31+
[3] (webpack)/test/statsCases/optimize-chunks/circular2.js 81 bytes {4} {6} [built]
32+
chunk {5} 5.js (chunk) 0 bytes {7} {1} [rendered]
33+
> chunk [7] (webpack)/test/statsCases/optimize-chunks/index.js 3:2-4:13
34+
> chunk [7] (webpack)/test/statsCases/optimize-chunks/index.js 9:1-10:12
35+
[4] (webpack)/test/statsCases/optimize-chunks/modules/c.js 0 bytes {5} {7} [built]
36+
[5] (webpack)/test/statsCases/optimize-chunks/modules/d.js 0 bytes {1} {5} [built]
37+
chunk {6} 6.js (cir2 from cir1) 81 bytes {0} [rendered]
38+
> cir2 from cir1 [2] (webpack)/test/statsCases/optimize-chunks/circular1.js 1:0-79
39+
[3] (webpack)/test/statsCases/optimize-chunks/circular2.js 81 bytes {4} {6} [built]
40+
[8] (webpack)/test/statsCases/optimize-chunks/modules/e.js 0 bytes {6} [built]
41+
chunk {7} 7.js (ac in ab) 0 bytes {2} [rendered]
42+
> ac in ab [7] (webpack)/test/statsCases/optimize-chunks/index.js 2:1-5:15
43+
[4] (webpack)/test/statsCases/optimize-chunks/modules/c.js 0 bytes {5} {7} [built]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
require.ensure(["./modules/a", "./modules/b"], function() {
2+
require.ensure(["./modules/a", "./modules/c"], function() {
3+
require.ensure(["./modules/a", "./modules/b"], function() {
4+
}, "chunk");
5+
}, "ac in ab");
6+
}, "ab");
7+
8+
require.ensure(["./modules/a", "./modules/b", "./modules/d"], function() {
9+
require.ensure(["./modules/c", "./modules/d"], function() {
10+
}, "chunk");
11+
}, "abd");
12+
13+
require.ensure(["./circular1"], function() {}, "cir1");
14+
require.ensure(["./circular2"], function() {}, "cir2");
15+
require("./modules/f");

test/statsCases/optimize-chunks/modules/a.js

Whitespace-only changes.

test/statsCases/optimize-chunks/modules/b.js

Whitespace-only changes.

test/statsCases/optimize-chunks/modules/c.js

Whitespace-only changes.

test/statsCases/optimize-chunks/modules/d.js

Whitespace-only changes.

test/statsCases/optimize-chunks/modules/e.js

Whitespace-only changes.

0 commit comments

Comments
 (0)