Skip to content

Commit 35ece08

Browse files
authored
Merge pull request webpack#4738 from webpack/perf/modules-set
Performance by using Set instead of Arrays
2 parents fba4e81 + 8d3efe7 commit 35ece08

File tree

6 files changed

+118
-54
lines changed

6 files changed

+118
-54
lines changed

lib/Compilation.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ class Compilation extends Tapable {
512512
if(err) return callback(err);
513513
deps.forEach(d => {
514514
if(d.module && d.module.removeReason(module, d)) {
515-
module.chunks.forEach(chunk => {
515+
module.forEachChunk(chunk => {
516516
if(!d.module.hasReasonForChunk(chunk)) {
517517
if(d.module.removeChunk(chunk)) {
518518
this.removeChunkFromDependencies(d.module, chunk);
@@ -1018,7 +1018,7 @@ class Compilation extends Tapable {
10181018

10191019
const modules = this.modules;
10201020
for(let indexModule = 0; indexModule < modules.length; indexModule++) {
1021-
modules[indexModule].sortItems();
1021+
modules[indexModule].sortItems(false);
10221022
}
10231023

10241024
const chunks = this.chunks;
@@ -1032,7 +1032,7 @@ class Compilation extends Tapable {
10321032

10331033
const modules = this.modules;
10341034
for(let indexModule = 0; indexModule < modules.length; indexModule++) {
1035-
modules[indexModule].sortItems();
1035+
modules[indexModule].sortItems(true);
10361036
}
10371037

10381038
const chunks = this.chunks;

lib/Module.js

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

7+
const util = require("util");
78
const DependenciesBlock = require("./DependenciesBlock");
89
const ModuleReason = require("./ModuleReason");
910
const Template = require("./Template");
@@ -19,6 +20,10 @@ function byId(a, b) {
1920
return a.id - b.id;
2021
}
2122

23+
function byDebugId(a, b) {
24+
return a.debugId - b.debugId;
25+
}
26+
2227
let debugId = 1000;
2328

2429
class Module extends DependenciesBlock {
@@ -36,7 +41,10 @@ class Module extends DependenciesBlock {
3641
this.used = null;
3742
this.usedExports = null;
3843
this.providedExports = null;
39-
this.chunks = [];
44+
this._chunks = new Set();
45+
this._chunksIsSorted = true;
46+
this._chunksIsSortedByDebugId = true;
47+
this._chunksDebugIdent = undefined;
4048
this.warnings = [];
4149
this.dependenciesWarnings = [];
4250
this.errors = [];
@@ -55,7 +63,9 @@ class Module extends DependenciesBlock {
5563
this.used = null;
5664
this.usedExports = null;
5765
this.providedExports = null;
58-
this.chunks.length = 0;
66+
this._chunks.clear();
67+
this._chunksDebugIdent = undefined;
68+
this._chunksIsSorted = this._chunksIsSortedByDebugId = false;
5969
super.disconnect();
6070
}
6171

@@ -65,26 +75,81 @@ class Module extends DependenciesBlock {
6575
this.index = null;
6676
this.index2 = null;
6777
this.depth = null;
68-
this.chunks.length = 0;
78+
this._chunks.clear();
79+
this._chunksDebugIdent = undefined;
80+
this._chunksIsSorted = this._chunksIsSortedByDebugId = false;
6981
super.unseal();
7082
}
7183

7284
addChunk(chunk) {
73-
let idx = this.chunks.indexOf(chunk);
74-
if(idx < 0)
75-
this.chunks.push(chunk);
85+
this._chunks.add(chunk);
86+
this._chunksDebugIdent = undefined;
87+
this._chunksIsSorted = this._chunksIsSortedByDebugId = false;
7688
}
7789

7890
removeChunk(chunk) {
79-
let idx = this.chunks.indexOf(chunk);
80-
if(idx >= 0) {
81-
this.chunks.splice(idx, 1);
91+
if(this._chunks.delete(chunk)) {
92+
this._chunksDebugIdent = undefined;
8293
chunk.removeModule(this);
8394
return true;
8495
}
8596
return false;
8697
}
8798

99+
isInChunk(chunk) {
100+
return this._chunks.has(chunk);
101+
}
102+
103+
getChunkIdsIdent() {
104+
if(this._chunksDebugIdent !== undefined) return this._chunksDebugIdent;
105+
this._ensureChunksSortedByDebugId();
106+
const chunks = this._chunks;
107+
const list = [];
108+
for(let chunk of chunks) {
109+
const debugId = chunk.debugId;
110+
111+
if(typeof debugId !== "number") {
112+
return this._chunksDebugIdent = null;
113+
}
114+
115+
list.push(debugId);
116+
}
117+
118+
return this._chunksDebugIdent = list.join(",");
119+
}
120+
121+
forEachChunk(fn) {
122+
this._chunks.forEach(fn);
123+
}
124+
125+
mapChunks(fn) {
126+
const chunks = this._chunks;
127+
const array = new Array(chunks.size);
128+
let idx = 0;
129+
for(let chunk of chunks) {
130+
array[idx++] = fn(chunk, idx, chunks);
131+
}
132+
return array;
133+
}
134+
135+
getNumberOfChunks() {
136+
return this._chunks.size;
137+
}
138+
139+
_ensureChunksSorted() {
140+
if(this._chunksIsSorted) return;
141+
this._chunks = new Set(Array.from(this._chunks).sort(byId));
142+
this._chunksIsSortedByDebugId = false;
143+
this._chunksIsSorted = true;
144+
}
145+
146+
_ensureChunksSortedByDebugId() {
147+
if(this._chunksIsSortedByDebugId) return;
148+
this._chunks = new Set(Array.from(this._chunks).sort(byDebugId));
149+
this._chunksIsSorted = false;
150+
this._chunksIsSortedByDebugId = true;
151+
}
152+
88153
addReason(module, dependency) {
89154
this.reasons.push(new ModuleReason(module, dependency));
90155
}
@@ -105,7 +170,7 @@ class Module extends DependenciesBlock {
105170
if(r.chunks) {
106171
if(r.chunks.indexOf(chunk) >= 0)
107172
return true;
108-
} else if(r.module.chunks.indexOf(chunk) >= 0)
173+
} else if(r.module._chunks.has(chunk))
109174
return true;
110175
}
111176
return false;
@@ -114,9 +179,9 @@ class Module extends DependenciesBlock {
114179
rewriteChunkInReasons(oldChunk, newChunks) {
115180
this.reasons.forEach(r => {
116181
if(!r.chunks) {
117-
if(r.module.chunks.indexOf(oldChunk) < 0)
182+
if(!r.module._chunks.has(oldChunk))
118183
return;
119-
r.chunks = r.module.chunks;
184+
r.chunks = Array.from(r.module._chunks);
120185
}
121186
r.chunks = r.chunks.reduce((arr, c) => {
122187
addToSet(arr, c !== oldChunk ? [c] : newChunks);
@@ -158,9 +223,10 @@ class Module extends DependenciesBlock {
158223
super.updateHash(hash);
159224
}
160225

161-
sortItems() {
226+
sortItems(sortChunks) {
162227
super.sortItems();
163-
this.chunks.sort(byId);
228+
if(sortChunks)
229+
this._ensureChunksSorted();
164230
this.reasons.sort((a, b) => byId(a.module, b.module));
165231
}
166232

@@ -178,6 +244,17 @@ Object.defineProperty(Module.prototype, "entry", {
178244
throw new Error("Module.entry was removed. Use Chunk.entryModule");
179245
}
180246
});
247+
248+
Object.defineProperty(Module.prototype, "chunks", {
249+
configurable: false,
250+
get: util.deprecate(() => {
251+
return Array.from(this._chunks);
252+
}, "Module.chunks: Use Module.forEachChunk/mapChunks/getNumberOfChunks/isInChunk/addChunk/removeChunk instead"),
253+
set() {
254+
throw new Error("Readonly. Use Module.addChunk/removeChunk to modify chunks.");
255+
}
256+
});
257+
181258
Module.prototype.identifier = null;
182259
Module.prototype.readableIdentifier = null;
183260
Module.prototype.build = null;

lib/ModuleFilenameHelpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ ModuleFilenameHelpers.createFooter = function createFooter(module, requestShorte
112112
"// WEBPACK FOOTER",
113113
`// ${module.readableIdentifier(requestShortener)}`,
114114
`// module id = ${module.id}`,
115-
`// module chunks = ${module.chunks.map(c => c.id).join(" ")}`
115+
`// module chunks = ${module.mapChunks(c => c.id).join(" ")}`
116116
].join("\n");
117117
}
118118
};

lib/Stats.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ class Stats {
280280
built: !!module.built,
281281
optional: !!module.optional,
282282
prefetched: !!module.prefetched,
283-
chunks: module.chunks.map(chunk => chunk.id),
283+
chunks: module.mapChunks(chunk => chunk.id),
284284
assets: Object.keys(module.assets || {}),
285285
issuer: module.issuer && module.issuer.identifier(),
286286
issuerId: module.issuer && module.issuer.id,

lib/optimize/OccurrenceOrderPlugin.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ class OccurrenceOrderPlugin {
1616
compiler.plugin("compilation", (compilation) => {
1717
compilation.plugin("optimize-module-order", (modules) => {
1818
function entryChunks(m) {
19-
return m.chunks.map((c) => {
19+
let total = 0;
20+
m.forEachChunk(c => {
2021
const sum = (c.isInitial() ? 1 : 0) + (c.entryModule === m ? 1 : 0);
21-
return sum;
22-
}).reduce((a, b) => {
23-
return a + b;
24-
}, 0);
22+
total += sum;
23+
});
24+
return total;
2525
}
2626

2727
function occursInEntry(m) {
@@ -37,14 +37,17 @@ class OccurrenceOrderPlugin {
3737

3838
function occurs(m) {
3939
if(typeof m.__OccurenceOrderPlugin_occurs === "number") return m.__OccurenceOrderPlugin_occurs;
40+
let numberEntry = 0;
41+
m.forEachChunk(c => {
42+
if(c.entryModule === m)
43+
numberEntry++;
44+
});
4045
const result = m.reasons.map((r) => {
4146
if(!r.module) return 0;
42-
return r.module.chunks.length;
47+
return r.module.getNumberOfChunks();
4348
}).reduce((a, b) => {
4449
return a + b;
45-
}, 0) + m.chunks.length + m.chunks.filter((c) => {
46-
return c.entryModule === m;
47-
}).length;
50+
}, 0) + m.getNumberOfChunks() + numberEntry;
4851
return m.__OccurenceOrderPlugin_occurs = result;
4952
}
5053
modules.sort((a, b) => {

lib/optimize/RemoveParentModulesPlugin.js

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,27 @@ function hasModule(chunk, module, checkedChunks) {
88
if(chunk.containsModule(module)) return [chunk];
99
if(chunk.parents.length === 0) return false;
1010
return allHaveModule(chunk.parents.filter((c) => {
11-
return checkedChunks.indexOf(c) < 0;
11+
return !checkedChunks.has(c);
1212
}), module, checkedChunks);
1313
}
1414

1515
function allHaveModule(someChunks, module, checkedChunks) {
16-
if(!checkedChunks) checkedChunks = [];
17-
var chunks = [];
16+
if(!checkedChunks) checkedChunks = new Set();
17+
var chunks = new Set();
1818
for(var i = 0; i < someChunks.length; i++) {
19-
checkedChunks.push(someChunks[i]);
19+
checkedChunks.add(someChunks[i]);
2020
var subChunks = hasModule(someChunks[i], module, checkedChunks);
2121
if(!subChunks) return false;
2222

2323
for(var index = 0; index < subChunks.length; index++) {
2424
var item = subChunks[index];
2525

26-
if(!chunks.length || chunks.indexOf(item) < 0) {
27-
chunks.push(item);
28-
}
26+
chunks.add(item);
2927
}
3028
}
3129
return chunks;
3230
}
3331

34-
function debugIds(chunks) {
35-
var list = [];
36-
for(var i = 0; i < chunks.length; i++) {
37-
var debugId = chunks[i].debugId;
38-
39-
if(typeof debugId !== "number") {
40-
return "no";
41-
}
42-
43-
list.push(debugId);
44-
}
45-
46-
list.sort();
47-
return list.join(",");
48-
}
49-
5032
class RemoveParentModulesPlugin {
5133
apply(compiler) {
5234
compiler.plugin("compilation", (compilation) => {
@@ -61,15 +43,17 @@ class RemoveParentModulesPlugin {
6143
for(var i = 0; i < modules.length; i++) {
6244
var module = modules[i];
6345

64-
var dId = debugIds(module.chunks);
46+
var dId = module.getChunkIdsIdent();
6547
var parentChunksWithModule;
66-
if((dId in cache) && dId !== "no") {
48+
if(dId === null) {
49+
parentChunksWithModule = allHaveModule(chunk.parents, module);
50+
} else if(dId in cache) {
6751
parentChunksWithModule = cache[dId];
6852
} else {
6953
parentChunksWithModule = cache[dId] = allHaveModule(chunk.parents, module);
7054
}
7155
if(parentChunksWithModule) {
72-
module.rewriteChunkInReasons(chunk, parentChunksWithModule);
56+
module.rewriteChunkInReasons(chunk, Array.from(parentChunksWithModule));
7357
chunk.removeModule(module);
7458
}
7559
}

0 commit comments

Comments
 (0)