Skip to content

Commit 5db5512

Browse files
committed
faster RemoveParentModule algorithm
1 parent bb5eb93 commit 5db5512

File tree

1 file changed

+60
-20
lines changed

1 file changed

+60
-20
lines changed

lib/optimize/RemoveParentModulesPlugin.js

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
"use strict";
66

7+
const Queue = require("../util/Queue");
8+
79
const hasModule = (chunk, module, checkedChunks) => {
810
if(chunk.containsModule(module)) return [chunk];
911
if(chunk.getNumberOfParents() === 0) return false;
@@ -33,30 +35,68 @@ class RemoveParentModulesPlugin {
3335
apply(compiler) {
3436
compiler.plugin("compilation", (compilation) => {
3537
compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"], (chunks) => {
36-
for(var index = 0; index < chunks.length; index++) {
37-
var chunk = chunks[index];
38-
if(chunk.getNumberOfParents() === 0) continue;
38+
const queue = new Queue(chunks);
39+
const availableModulesMap = new Map();
3940

40-
// TODO consider Map when performance has improved https://gist.github.com/sokra/b36098368da7b8f6792fd7c85fca6311
41-
var cache = Object.create(null);
42-
var modules = chunk.getModules();
43-
for(var i = 0; i < modules.length; i++) {
44-
var module = modules[i];
41+
for(const chunk of chunks) {
42+
// initialize available modules for chunks without parents
43+
if(chunk.getNumberOfParents() === 0)
44+
availableModulesMap.set(chunk, new Set());
45+
}
4546

46-
var dId = module.getChunkIdsIdent();
47-
var parentChunksWithModule;
48-
if(dId === null) {
49-
parentChunksWithModule = allHaveModule(chunk.getParents(), module);
50-
} else if(dId in cache) {
51-
parentChunksWithModule = cache[dId];
52-
} else {
53-
parentChunksWithModule = cache[dId] = allHaveModule(chunk.getParents(), module);
54-
}
55-
if(parentChunksWithModule) {
56-
module.rewriteChunkInReasons(chunk, Array.from(parentChunksWithModule));
57-
chunk.removeModule(module);
47+
while(queue.length > 0) {
48+
const chunk = queue.dequeue();
49+
let availableModules = availableModulesMap.get(chunk);
50+
let changed = false;
51+
for(const parent of chunk.parentsIterable) {
52+
const availableModulesInParent = availableModulesMap.get(parent);
53+
if(availableModulesInParent !== undefined) {
54+
// If we know the available modules in parent: process these
55+
if(availableModules === undefined) {
56+
// if we have not own info yet: create new entry
57+
availableModules = new Set(availableModulesInParent);
58+
for(const m of parent.modulesIterable)
59+
availableModules.add(m);
60+
availableModulesMap.set(chunk, availableModules);
61+
changed = true;
62+
} else {
63+
for(const m of availableModules) {
64+
if(!parent.containsModule(m) && !availableModulesInParent.has(m)) {
65+
availableModules.delete(m);
66+
changed = true;
67+
}
68+
}
69+
}
5870
}
5971
}
72+
if(changed) {
73+
// if something changed: enqueue our children
74+
for(const child of chunk.chunksIterable)
75+
queue.enqueue(child);
76+
}
77+
}
78+
79+
// now we have available modules for every chunk
80+
81+
for(const chunk of chunks) {
82+
// remove modules from chunk if they are already available
83+
const availableModules = availableModulesMap.get(chunk);
84+
const modules = new Set(chunk.modulesIterable);
85+
const toRemove = new Set();
86+
if(modules.size < availableModules.size) {
87+
for(const m of modules)
88+
if(availableModules.has(m))
89+
toRemove.add(m);
90+
} else {
91+
for(const m of availableModules)
92+
if(modules.has(m))
93+
toRemove.add(m);
94+
}
95+
for(const module of toRemove) {
96+
const parentChunksWithModule = allHaveModule(chunk.getParents(), module);
97+
module.rewriteChunkInReasons(chunk, Array.from(parentChunksWithModule));
98+
chunk.removeModule(module);
99+
}
60100
}
61101
});
62102
});

0 commit comments

Comments
 (0)