Skip to content

Commit e5349ad

Browse files
committed
WIP10
1 parent d5aae9d commit e5349ad

File tree

6 files changed

+148
-128
lines changed

6 files changed

+148
-128
lines changed

lib/Compilation.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,10 +1339,9 @@ class Compilation extends Tapable {
13391339
let nextFreeModuleId = 0;
13401340
const usedIds = new Set();
13411341
if(this.usedModuleIds) {
1342-
Object.keys(this.usedModuleIds).forEach(key => {
1343-
const id = this.usedModuleIds[key];
1342+
for(const id of this.usedModuleIds) {
13441343
usedIds.add(id);
1345-
});
1344+
}
13461345
}
13471346

13481347
const modules1 = this.modules;
@@ -1389,17 +1388,13 @@ class Compilation extends Tapable {
13891388

13901389
// Get used ids from usedChunkIds property (i. e. from records)
13911390
if(this.usedChunkIds) {
1392-
const keyChunks = Object.keys(this.usedChunkIds);
1391+
for(const id of this.usedChunkIds) {
13931392

1394-
for(let index = 0; index < keyChunks.length; index++) {
1395-
const usedIdKey = keyChunks[index];
1396-
const usedIdValue = this.usedChunkIds[usedIdKey];
1397-
1398-
if(typeof usedIdValue !== "number") {
1393+
if(typeof id !== "number") {
13991394
continue;
14001395
}
14011396

1402-
usedIds.add(usedIdValue);
1397+
usedIds.add(id);
14031398
}
14041399
}
14051400

@@ -1415,24 +1410,27 @@ class Compilation extends Tapable {
14151410

14161411
usedIds.add(usedIdValue);
14171412
}
1413+
console.log("Compilation usedIds = ", usedIds);
14181414

14191415
// Calculate maximum assigned chunk id
14201416
let nextFreeChunkId = -1;
14211417
for(const id of usedIds) {
14221418
nextFreeChunkId = Math.max(nextFreeChunkId, id);
14231419
}
14241420
nextFreeChunkId++;
1421+
console.log("Compilation nextFreeChunkId = ", nextFreeChunkId);
14251422

14261423
// Determine free chunk ids from 0 to maximum
14271424
const unusedIds = [];
14281425
if(nextFreeChunkId > 0) {
14291426
let index = nextFreeChunkId;
14301427
while(index--) {
1431-
if(usedIds.has(index)) {
1428+
if(!usedIds.has(index)) {
14321429
unusedIds.push(index);
14331430
}
14341431
}
14351432
}
1433+
console.log("Compilation unusedIds = ", unusedIds);
14361434

14371435
// Assign ids to chunk which has no id
14381436
for(let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {

lib/RecordIdsPlugin.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class RecordIdsPlugin {
3838
module.id = id;
3939
});
4040
}
41-
compilation.usedModuleIds = records.modules.usedIds;
41+
compilation.usedModuleIds = new Set(records.modules.usedIds);
4242
});
4343

4444
const getModuleIdentifier = module => {
@@ -69,18 +69,20 @@ class RecordIdsPlugin {
6969
if(!records.chunks) records.chunks = {};
7070
if(!records.chunks.byName) records.chunks.byName = {};
7171
if(!records.chunks.bySource) records.chunks.bySource = {};
72-
records.chunks.usedIds = {};
72+
const usedIds = new Set();
7373
chunks.forEach(chunk => {
7474
const name = chunk.name;
7575
if(name) records.chunks.byName[name] = chunk.id;
7676
const sources = getChunkSources(chunk);
7777
for(const source of sources) {
7878
records.chunks.bySource[source] = chunk.id;
7979
}
80-
records.chunks.usedIds[chunk.id] = chunk.id;
80+
usedIds.add(chunk.id);
8181
});
82+
records.chunks.usedIds = Array.from(usedIds);
8283
});
8384
compilation.hooks.reviveChunks.tap("RecordIdsPlugin", (chunks, records) => {
85+
console.log("RecordIdsPlugin.reviveChunks");
8486
if(!records.chunks) return;
8587
const usedIds = new Set();
8688
if(records.chunks.byName) {
@@ -91,6 +93,7 @@ class RecordIdsPlugin {
9193
if(id === undefined) return;
9294
if(usedIds.has(id)) return;
9395
usedIds.add(id);
96+
console.log(`RecordsIdPlugin: assign chunk id ${id}`);
9497
chunk.id = id;
9598
});
9699
}
@@ -103,11 +106,12 @@ class RecordIdsPlugin {
103106
if(usedIds[id]) continue;
104107
usedIds[id] = true;
105108
chunk.id = id;
109+
console.log(`RecordsIdPlugin: assign chunk id ${id}`);
106110
break;
107111
}
108112
});
109113
}
110-
compilation.usedChunkIds = records.chunks.usedIds;
114+
compilation.usedChunkIds = new Set(records.chunks.usedIds);
111115
});
112116
});
113117
}

lib/optimize/AggressiveSplittingPlugin.js

Lines changed: 88 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"use strict";
66

77
const identifierUtils = require("../util/identifier");
8+
const intersect = require("../util/SetHelpers").intersect;
89
const validateOptions = require("schema-utils");
910
const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json");
1011

@@ -20,16 +21,6 @@ const isNotAEntryModule = entryModule => {
2021
};
2122
};
2223

23-
const copyWithReason = obj => {
24-
const newObj = {};
25-
Object.keys(obj).forEach(key => {
26-
newObj[key] = obj[key];
27-
});
28-
if(!newObj.reasons || !newObj.reasons.includes("aggressive-splitted"))
29-
newObj.reasons = (newObj.reasons || []).concat("aggressive-splitted");
30-
return newObj;
31-
};
32-
3324
class AggressiveSplittingPlugin {
3425
constructor(options) {
3526
validateOptions(schema, options || {}, "Aggressive Splitting Plugin");
@@ -39,10 +30,17 @@ class AggressiveSplittingPlugin {
3930
if(typeof this.options.maxSize !== "number") this.options.maxSize = 50 * 1024;
4031
if(typeof this.options.chunkOverhead !== "number") this.options.chunkOverhead = 0;
4132
if(typeof this.options.entryChunkMultiplicator !== "number") this.options.entryChunkMultiplicator = 1;
33+
34+
this.usedSplitsMap = new WeakMap();
35+
this.fromAggressiveSplittingSet = new WeakSet();
36+
this.aggressiveSplittingInvalidSet = new WeakSet();
37+
this.fromAggressiveSplittingIndexMap = new WeakMap();
4238
}
4339
apply(compiler) {
4440
compiler.hooks.thisCompilation.tap("AggressiveSplittingPlugin", (compilation) => {
4541
compilation.hooks.optimizeChunksAdvanced.tap("AggressiveSplittingPlugin", (chunks) => {
42+
for(const chunk of chunks)
43+
console.log(`${chunk.debugId} =\n${Array.from(chunk.modulesIterable, m => ` * ${m.resource}`).join("\n")}`);
4644
// Precompute stuff
4745
const nameToModuleMap = new Map();
4846
compilation.modules.forEach(m => {
@@ -51,18 +49,44 @@ class AggressiveSplittingPlugin {
5149
});
5250

5351
const savedSplits = compilation.records && compilation.records.aggressiveSplits || [];
54-
const usedSplits = compilation._aggressiveSplittingSplits ?
55-
savedSplits.concat(compilation._aggressiveSplittingSplits) : savedSplits;
52+
let storedSplits = this.usedSplitsMap.get(compilation);
53+
const usedSplits = storedSplits ?
54+
savedSplits.concat(storedSplits) : savedSplits;
5655

5756
const minSize = this.options.minSize;
5857
const maxSize = this.options.maxSize;
5958
// 1. try to restore to recorded splitting
6059
for(let j = 0; j < usedSplits.length; j++) {
6160
const splitData = usedSplits[j];
6261
const selectedModules = splitData.modules.map(name => nameToModuleMap.get(name));
62+
console.log("Try to split", splitData);
6363

6464
// Does the modules exist at all?
65-
if(selectedModules.every(Boolean)) {
65+
if(!selectedModules.every(Boolean)) continue;
66+
console.log("modules ok");
67+
68+
const selectedChunks = intersect(selectedModules.map(m => new Set(m.chunksIterable)));
69+
70+
// No relevant chunks found
71+
if(selectedChunks.size === 0) continue;
72+
73+
// The found chunk is already the split or similar
74+
if(selectedChunks.size === 1 && Array.from(selectedChunks)[0].getNumberOfModules() === selectedModules.length) continue;
75+
76+
// split the chunk into two parts
77+
const newChunk = compilation.addChunk();
78+
for(const chunk of selectedChunks) {
79+
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
80+
chunk.split(newChunk);
81+
chunk.name = null;
82+
}
83+
this.fromAggressiveSplittingSet.add(newChunk);
84+
if(j < savedSplits.length)
85+
this.fromAggressiveSplittingIndexMap.set(newChunk, j);
86+
if(splitData.id !== null && splitData.id !== undefined) {
87+
console.log(`AggressiveSplittingPlugin assign id ${splitData.id}`);
88+
newChunk.id = splitData.id;
89+
}
6690

6791
// Find all chunks containing all modules in the split
6892
for(let i = 0; i < chunks.length; i++) {
@@ -75,26 +99,48 @@ class AggressiveSplittingPlugin {
7599
// Check if all modules are in the chunk
76100
if(selectedModules.every(m => chunk.containsModule(m))) {
77101

78-
// Is chunk identical to the split or do we need to split it?
79-
if(chunk.getNumberOfModules() > splitData.modules.length) {
80-
// split the chunk into two parts
81-
const newChunk = compilation.addChunk();
82-
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
83-
chunk.split(newChunk);
84-
chunk.name = null;
85-
newChunk._fromAggressiveSplitting = true;
86-
if(j < savedSplits.length)
87-
newChunk._fromAggressiveSplittingIndex = j;
88-
if(splitData.id !== null && splitData.id !== undefined) {
89-
newChunk.id = splitData.id;
102+
console.log("found chunk " + chunk.debugId);
103+
104+
const existingSplit = this.xxx.get(splitData);
105+
106+
// Did we already create a chunk for this split?
107+
if(existingSplit !== undefined) {
108+
console.log("use existing split");
109+
// Is chunk identical to the split or do we need to split it?
110+
if(chunk.getNumberOfModules() > splitData.modules.length) {
111+
selectedModules.forEach(moveModuleBetween(chunk, existingSplit));
112+
chunk.split(existingSplit);
113+
chunk.name = null;
114+
} else {
115+
if(existingSplit.integrate(chunk, "aggressive-splitting"))
116+
chunks.splice(i--, 1);
90117
}
91-
return true;
92-
} else { // chunk is identical to the split
93-
if(j < savedSplits.length)
94-
chunk._fromAggressiveSplittingIndex = j;
95-
chunk.name = null;
96-
if(splitData.id !== null && splitData.id !== undefined) {
97-
chunk.id = splitData.id;
118+
} else {
119+
// Is chunk identical to the split or do we need to split it?
120+
if(chunk.getNumberOfModules() > splitData.modules.length) {
121+
// split the chunk into two parts
122+
const newChunk = compilation.addChunk();
123+
selectedModules.forEach(moveModuleBetween(chunk, newChunk));
124+
chunk.split(newChunk);
125+
chunk.name = null;
126+
this.xxx.set(splitData, newChunk);
127+
this.fromAggressiveSplittingSet.add(newChunk);
128+
if(j < savedSplits.length)
129+
this.fromAggressiveSplittingIndexMap.set(newChunk, j);
130+
if(splitData.id !== null && splitData.id !== undefined) {
131+
console.log(`AggressiveSplittingPlugin assign id ${splitData.id}`);
132+
newChunk.id = splitData.id;
133+
}
134+
return true;
135+
} else { // chunk is identical to the split
136+
if(j < savedSplits.length)
137+
this.fromAggressiveSplittingIndexMap.set(chunk, j);
138+
chunk.name = null;
139+
this.xxx.set(splitData, chunk);
140+
if(splitData.id !== null && splitData.id !== undefined) {
141+
console.log(`AggressiveSplittingPlugin assign id ${splitData.id}`);
142+
chunk.id = splitData.id;
143+
}
98144
}
99145
}
100146
}
@@ -139,9 +185,10 @@ class AggressiveSplittingPlugin {
139185
if(newChunk.getNumberOfModules() > 0) {
140186
chunk.split(newChunk);
141187
chunk.name = null;
142-
compilation._aggressiveSplittingSplits = (compilation._aggressiveSplittingSplits || []).concat({
188+
storedSplits = (storedSplits || []).concat({
143189
modules: newChunk.mapModules(m => identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache))
144190
});
191+
this.usedSplitsMap.set(compilation, storedSplits);
145192
return true;
146193
} else {
147194
chunks.splice(chunks.indexOf(newChunk), 1);
@@ -160,7 +207,8 @@ class AggressiveSplittingPlugin {
160207
const size = chunk.size(this.options);
161208
const incorrectSize = size < minSize;
162209
const modules = chunk.mapModules(m => identifierUtils.makePathsRelative(compiler.context, m.identifier(), compilation.cache));
163-
if(typeof chunk._fromAggressiveSplittingIndex === "undefined") {
210+
const index = this.fromAggressiveSplittingIndexMap.get(chunk);
211+
if(typeof index === "undefined") {
164212
if(incorrectSize) return;
165213
// this is a new chunk splitting, we record it so we reuse it next time
166214
chunk.recorded = true;
@@ -170,29 +218,31 @@ class AggressiveSplittingPlugin {
170218
id: chunk.id
171219
});
172220
} else {
173-
const splitData = records.aggressiveSplits[chunk._fromAggressiveSplittingIndex];
221+
const splitData = records.aggressiveSplits[index];
174222
if(splitData.hash !== chunk.hash || incorrectSize) {
175-
if(chunk._fromAggressiveSplitting) {
176-
chunk._aggressiveSplittingInvalid = true;
223+
if(this.fromAggressiveSplittingSet.has(chunk)) {
224+
this.aggressiveSplittingInvalidSet.add(chunk);
177225
splitData.invalid = true;
178226
splittingInvalid = true;
179227
} else {
180228
splitData.hash = chunk.hash;
181229
}
182230
}
231+
console.log(splitData);
183232
}
184233
});
185234
if(splittingInvalid) {
186235
records.aggressiveSplits = records.aggressiveSplits.filter((splitData) => {
187236
return !splitData.invalid;
188237
});
189238
} else {
239+
console.log(newSplits);
190240
records.aggressiveSplits = records.aggressiveSplits.concat(newSplits);
191241
}
192242
});
193243
compilation.hooks.needAdditionalSeal.tap("AggressiveSplittingPlugin", () => {
194244
const invalid = compilation.chunks.some((chunk) => {
195-
return chunk._aggressiveSplittingInvalid;
245+
return this.aggressiveSplittingInvalidSet.has(chunk);
196246
});
197247
if(invalid)
198248
return true;

lib/optimize/RemoveParentModulesPlugin.js

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"use strict";
66

77
const Queue = require("../util/Queue");
8-
const ChunkGroup = require("../ChunkGroup");
8+
const intersect = require("../util/SetHelpers").intersect;
99

1010
const getParentChunksWithModule = (currentChunk, module) => {
1111
const chunks = [];
@@ -24,31 +24,6 @@ const getParentChunksWithModule = (currentChunk, module) => {
2424
return chunks;
2525
};
2626

27-
const intersect = sets => {
28-
if(sets.length === 0) return new Set();
29-
if(sets.length === 1) return new Set(sets[0]);
30-
let minSize = Infinity;
31-
let minIndex = -1;
32-
for(let i = 0; i < sets.length; i++) {
33-
const size = sets[i].size;
34-
if(size < minSize) {
35-
minIndex = i;
36-
minSize = size;
37-
}
38-
}
39-
const current = new Set(sets[minSize]);
40-
for(let i = 0; i < sets.length; i++) {
41-
if(i === minIndex) continue;
42-
const set = sets[i];
43-
for(const item of current) {
44-
if(!set.has(item)) {
45-
current.delete(item);
46-
}
47-
}
48-
}
49-
return current;
50-
}
51-
5227
class RemoveParentModulesPlugin {
5328
apply(compiler) {
5429
compiler.hooks.compilation.tap("RemoveParentModulesPlugin", (compilation) => {

0 commit comments

Comments
 (0)