Skip to content

Commit 9eb5d6b

Browse files
committed
WIP4
1 parent 91d3661 commit 9eb5d6b

File tree

27 files changed

+251
-173
lines changed

27 files changed

+251
-173
lines changed

lib/AsyncDependenciesBlock.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
1515
this.request = request;
1616
}
1717

18+
get chunks() {
19+
throw new Error("Moved to AsyncDependenciesBlock.chunkGroup");
20+
}
21+
22+
set chunks(value) {
23+
throw new Error("Moved to AsyncDependenciesBlock.chunkGroup");
24+
}
25+
1826
updateHash(hash) {
1927
hash.update(this.chunkName || "");
2028
hash.update(this.chunkGroup && this.chunkGroup.chunks.map(chunk => {

lib/Chunk.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class Chunk {
217217
split(newChunk) {
218218
for(const chunkGroup of this._groups) {
219219
chunkGroup.insertChunk(newChunk, this);
220+
newChunk.addGroup(chunkGroup);
220221
}
221222
}
222223

lib/Compilation.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,9 +1074,6 @@ class Compilation extends Tapable {
10741074
c = this.addChunkInGroup(b.chunkName, module, b.loc, b.request);
10751075
blockChunkGroups.set(b, c);
10761076
allCreatedChunkGroups.add(c);
1077-
// We initialize the chunks property
1078-
// this is later filled with the chunk when needed
1079-
b.chunks = [];
10801077
}
10811078
} else {
10821079
c.addOrigin(module, b.loc, b.request);
@@ -1232,9 +1229,7 @@ class Compilation extends Tapable {
12321229
const depBlock = dep.block;
12331230

12341231
// 6. Connnect block with chunk
1235-
if(depChunkGroup.addBlock(depBlock)) {
1236-
depBlock.chunkGroup = depChunkGroup;
1237-
}
1232+
GraphHelpers.connectDependenciesBlockAndChunkGroup(depBlock, depChunkGroup);
12381233

12391234
// 7. Connect chunk with parent
12401235
GraphHelpers.connectChunkGroupParentAndChild(chunkGroup, depChunkGroup);

lib/GraphHelpers.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const Chunk = require("./Chunk");
22
const ChunkGroup = require("./ChunkGroup");
33
const Module = require("./Module");
4+
const DependenciesBlock = require("./DependenciesBlock");
45

56
// TODO remove this function
67
function assert(value, Type, name) {
@@ -31,3 +32,11 @@ exports.connectChunkAndModule = (chunk, module) => {
3132
chunk.addModule(module);
3233
}
3334
};
35+
36+
exports.connectDependenciesBlockAndChunkGroup = (depBlock, chunkGroup) => {
37+
assert(depBlock, DependenciesBlock, "depBlock");
38+
assert(chunkGroup, ChunkGroup, "chunkGroup");
39+
if(chunkGroup.addBlock(depBlock)) {
40+
depBlock.chunkGroup = chunkGroup;
41+
}
42+
}

lib/RuntimeTemplate.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ module.exports = class RuntimeTemplate {
254254
block,
255255
message
256256
}) {
257+
console.log("blockPromise", block.chunkGroup)
257258
if(!block || !block.chunkGroup || block.chunkGroup.chunks.length === 0) {
258259
const comment = this.comment({
259260
message

lib/Stats.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ class Stats {
443443
}
444444
if(showChunkOrigins) {
445445
obj.origins = Array.from(chunk.groupsIterable, g => g.origins)
446-
.reduce((a, b) => (a.push(b), a), [])
446+
.reduce((a, b) => a.concat(b), [])
447447
.map(origin => ({
448448
moduleId: origin.module ? origin.module.id : undefined,
449449
module: origin.module ? origin.module.identifier() : "",
@@ -903,6 +903,11 @@ class Stats {
903903
colors.yellow(` ${chunk.reason}`);
904904
}
905905
newline();
906+
for(const group of chunk.siblings) {
907+
colors.normal(" > ");
908+
colors.normal(`[${group.join(" + ")}]`);
909+
newline();
910+
}
906911
if(chunk.origins) {
907912
chunk.origins.forEach(origin => {
908913
colors.normal(" > ");

lib/WebpackOptionsApply.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,26 @@ class WebpackOptionsApply extends OptionsApply {
287287
new FlagDependencyUsagePlugin().apply(compiler);
288288
if(options.optimization.concatenateModules)
289289
new ModuleConcatenationPlugin().apply(compiler);
290+
const normalizeCommonsChunksNameOption = value => {
291+
if(value === true) {
292+
return (module, chunks) => {
293+
const names = chunks.map(c => c.name);
294+
if(!names.every(Boolean)) return;
295+
names.sort();
296+
return names.join("-");
297+
};
298+
} else if(typeof value === "string") {
299+
return (module, chunks) => {
300+
return value;
301+
};
302+
} else {
303+
return value;
304+
}
305+
}
290306
if(options.optimization.asyncCommonsChunks) {
291307
const accpOptions = Object.assign({}, options.optimization.asyncCommonsChunks, {
292-
initialChunks: false
308+
initialChunks: false,
309+
name: normalizeCommonsChunksNameOption(typeof options.optimization.asyncCommonsChunks === "object" ? options.optimization.asyncCommonsChunks.name : undefined)
293310
});
294311
new AutomaticCommonsChunksPlugin(accpOptions).apply(compiler);
295312
}
@@ -306,7 +323,7 @@ class WebpackOptionsApply extends OptionsApply {
306323
};
307324
}
308325
if(nameOption && typeof nameOption === "object") {
309-
nameOption = ((nameOption) => ((module, compilation) => {
326+
nameOption = ((nameOption) => ((module, chunks) => {
310327
if(!module.nameForCondition) return;
311328
const name = module.nameForCondition();
312329
for(const chunkName of Object.keys(nameOption)) {
@@ -327,10 +344,23 @@ class WebpackOptionsApply extends OptionsApply {
327344
}
328345
}))(nameOption);
329346
}
347+
let commonsNameOption = normalizeCommonsChunksNameOption(typeof options.optimization.initialCommonsChunks === "object" ? options.optimization.initialCommonsChunks.name : undefined);
348+
let name;
349+
if(commonsNameOption && !nameOption) {
350+
name = commonsNameOption;
351+
} else if(commonsNameOption) {
352+
name = (module, chunks) => {
353+
const r = nameOption(module, chunks);
354+
if(r !== undefined) return r;
355+
return commonsNameOption(module, chunks);
356+
};
357+
} else {
358+
name = nameOption;
359+
}
330360
const accpOptions = Object.assign({}, options.optimization.initialCommonsChunks, {
331361
initialChunks: true,
332362
onlyNamed: !options.optimization.initialCommonsChunks,
333-
name: nameOption
363+
name
334364
});
335365
new AutomaticCommonsChunksPlugin(accpOptions).apply(compiler);
336366
}

lib/optimize/AutomaticCommonsChunksPlugin.js

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

77
const SortableSet = require("../util/SortableSet");
8+
const GraphHelpers = require("../GraphHelpers");
89

910
const sortByIdentifier = (a, b) => {
1011
if(a.identifier() > b.identifier()) return 1;
@@ -13,20 +14,23 @@ const sortByIdentifier = (a, b) => {
1314
};
1415

1516
const getRequests = chunk => {
16-
return Math.max(
17-
chunk.mapBlocks(block => block.chunks.length).reduce(Math.max, 0),
18-
chunk.mapEntrypoints(ep => ep.chunks.length).reduce(Math.max, 0)
19-
);
17+
let requests = 0;
18+
for(const chunkGroup of chunk.groupsIterable) {
19+
requests = Math.max(requests, chunkGroup.chunks.length);
20+
}
21+
return requests;
2022
};
2123

2224
module.exports = class AutomaticCommonsChunksPlugin {
2325
constructor(options) {
2426
this.options = Object.assign({}, {
2527
initialChunks: false,
2628
minSize: 30000,
29+
minChunks: 2,
2730
maxRequests: 4,
2831
onlyNamed: false,
29-
name: undefined
32+
name: undefined, // function(module, chunks) => string | undefined
33+
enforce: undefined // function(module, module) => true | false
3034
}, options);
3135
}
3236

@@ -42,58 +46,67 @@ module.exports = class AutomaticCommonsChunksPlugin {
4246
}
4347
// Map a list of chunks to a list of modules
4448
// For the key the chunk "index" is used, the value is a SortableSet of modules
45-
const chunksModulesMap = new Map();
46-
// Map a list of chunks to a name (not every list of chunks is mapped, only when "name" option is used)
47-
const chunksNameMap = new Map();
49+
const chunksInfoMap = new Map();
4850
// Walk through all modules
4951
for(const module of compilation.modules) {
5052
// Get indices of chunks in which this module occurs
5153
const chunkIndices = Array.from(module.chunksIterable, chunk => indexMap.get(chunk)).filter(Boolean);
54+
// Get array of chunks
55+
const chunks = Array.from(module.chunksIterable).filter(chunk => indexMap.get(chunk) !== undefined);
56+
// Get enforce from "enforce" option
57+
let enforce = this.options.enforce;
58+
if(typeof enforce === "function")
59+
enforce = enforce(module, chunks);
60+
// Break if minimum number of chunks is not reached
61+
if(!enforce && chunkIndices.length < this.options.minChunks)
62+
continue;
5263
// Get name from "name" option
5364
let name = this.options.name;
5465
if(typeof name === "function")
55-
name = name(module);
56-
if(name) {
57-
chunkIndices.push(`[${name}]`);
58-
} else if(this.options.onlyNamed) {
59-
// May skip unnamed chunks if "onlyNamed" is used
60-
continue;
61-
}
62-
// skip for modules which are only in one chunk or don't get a name
63-
if(chunkIndices.length <= 1) continue;
66+
name = name(module, chunks);
6467
// Create key for maps
65-
const key = chunkIndices.sort().join();
68+
// When it has a name we use the name as key
69+
// Elsewise we create the key from chunks
70+
// This automatically merges equal names
71+
const chunksKey = chunkIndices.sort().join();
72+
const key = name ? name : chunksKey;
6673
// Add module to maps
67-
let modules = chunksModulesMap.get(key);
68-
if(modules === undefined) {
69-
chunksModulesMap.set(key, modules = new SortableSet(undefined, sortByIdentifier));
70-
if(name) {
71-
// Note name when used
72-
chunksNameMap.set(key, name);
74+
let info = chunksInfoMap.get(key);
75+
if(info === undefined) {
76+
chunksInfoMap.set(key, info = {
77+
modules: new SortableSet(undefined, sortByIdentifier),
78+
enforce,
79+
name,
80+
chunks: new Set(),
81+
chunksKeys: new Set()
82+
});
83+
}
84+
info.modules.add(module);
85+
if(!info.chunksKeys.has(chunksKey)) {
86+
info.chunksKeys.add(chunksKey);
87+
for(const chunk of chunks) {
88+
info.chunks.add(chunk);
7389
}
7490
}
75-
modules.add(module);
7691
}
7792
// Get size of module lists and sort them by name and size
78-
const entries = Array.from(chunksModulesMap.entries(), pair => {
79-
const modules = pair[1];
80-
const size = Array.from(modules, m => m.size()).reduce((a, b) => a + b, 0);
81-
return {
82-
key: pair[0],
83-
modules,
84-
size
85-
};
93+
const entries = Array.from(chunksInfoMap.entries(), pair => {
94+
const info = pair[1];
95+
info.key = pair[0];
96+
info.size = Array.from(info.modules, m => m.size()).reduce((a, b) => a + b, 0);
97+
return info;
98+
}).filter(item => {
99+
if(item.enforce) return true;
100+
// Filter by size limit
101+
if(item.size < this.options.minSize) return false;
102+
return true;
86103
}).sort((a, b) => {
87104
// Sort
88-
// 1. by chunk name
89-
const chunkNameA = chunksNameMap.get(a.key);
90-
const chunkNameB = chunksNameMap.get(b.key);
91-
if(chunkNameA && !chunkNameB) return -1;
92-
if(!chunkNameA && chunkNameB) return 1;
93-
if(chunkNameA && chunkNameB) {
94-
if(chunkNameA < chunkNameB) return -1;
95-
if(chunkNameA > chunkNameB) return 1;
96-
}
105+
// 1. by enforced (enforce first)
106+
const enforcedA = a.enforce;
107+
const enforcedB = b.enforce;
108+
if(enforcedA && !enforcedB) return -1;
109+
if(!enforcedA && enforcedB) return 1;
97110
// 2. by total modules size
98111
const diffSize = b.size - a.size;
99112
if(diffSize) return diffSize;
@@ -120,24 +133,22 @@ module.exports = class AutomaticCommonsChunksPlugin {
120133
let changed = false;
121134
// Walk though all entries
122135
for(const item of entries) {
123-
const chunkName = chunksNameMap.get(item.key);
124-
// Skip if size is smaller than minimum size
125-
if(!chunkName && item.size < this.options.minSize) continue;
136+
const chunkName = item.name;
137+
const enforced = item.enforce;
126138
// Variable for the new chunk (lazy created)
127139
let newChunk;
128140
// Walk through all chunks
129-
// All modules have the same chunks so we can use the first module
130-
const firstModule = item.modules.values().next().value;
131-
for(const chunk of firstModule.chunksIterable) {
141+
for(const chunk of item.chunks) {
132142
// skip if we address ourself
133143
if(chunk.name === chunkName) continue;
134-
// only use selected chunks
135-
if(!indexMap.get(chunk)) continue;
136144
// respect max requests when not a named chunk
137-
if(!chunkName && getRequests(chunk) >= this.options.maxRequests) continue;
145+
if(!enforced && getRequests(chunk) >= this.options.maxRequests) continue;
138146
if(newChunk === undefined) {
139147
// Create the new chunk
140-
newChunk = compilation.addChunk(chunkName);
148+
newChunk = compilation.addChunk();
149+
if(chunkName) {
150+
newChunk.name = chunkName;
151+
}
141152
}
142153
// Add graph connections for splitted chunk
143154
chunk.split(newChunk);
@@ -149,20 +160,20 @@ module.exports = class AutomaticCommonsChunksPlugin {
149160
}
150161
// If we successfully creates a new chunk
151162
if(newChunk) {
163+
// Add a note to the chunk
164+
newChunk.chunkReason = enforced ? "vendors chunk" : "commons chunk";
152165
// If the choosen name is already an entry point we remove the entry point
153166
if(chunkName) {
154-
const entrypoint = compilation.entrypoints[chunkName];
167+
const entrypoint = compilation.entrypoints.get(chunkName);
155168
if(entrypoint) {
156-
delete compilation.entrypoints[chunkName];
169+
compilation.entrypoints.delete(chunkName);
157170
entrypoint.remove();
158171
}
172+
newChunk.chunkReason += " " + chunkName;
159173
}
160-
// Add a note to the chunk
161-
newChunk.chunkReason = chunkName ? "vendors chunk" : "commons chunk";
162174
// Add all modules to the new chunk
163175
for(const module of item.modules) {
164-
newChunk.addModule(module);
165-
module.addChunk(newChunk);
176+
GraphHelpers.connectChunkAndModule(newChunk, module);
166177
}
167178
changed = true;
168179
}

lib/webpack.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ exportPlugins(exports.optimize = {}, {
107107
"AggressiveMergingPlugin": () => require("./optimize/AggressiveMergingPlugin"),
108108
"AggressiveSplittingPlugin": () => require("./optimize/AggressiveSplittingPlugin"),
109109
"AutomaticCommonsChunksPlugin": () => require("./optimize/AutomaticCommonsChunksPlugin"),
110-
"CommonsChunkPlugin": () => require("./optimize/CommonsChunkPlugin"),
111110
"ChunkModuleIdRangePlugin": () => require("./optimize/ChunkModuleIdRangePlugin"),
112111
"LimitChunkCountPlugin": () => require("./optimize/LimitChunkCountPlugin"),
113112
"MinChunkSizePlugin": () => require("./optimize/MinChunkSizePlugin"),

0 commit comments

Comments
 (0)