Skip to content

Commit ec4ec8e

Browse files
authored
Merge pull request webpack#7056 from webpack/feature/preload
add support for link preload/prefetch
2 parents 0ff2901 + 8e2e19b commit ec4ec8e

File tree

76 files changed

+795
-154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+795
-154
lines changed

lib/AsyncDependenciesBlock.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,28 @@
66
const DependenciesBlock = require("./DependenciesBlock");
77

88
module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
9-
constructor(name, module, loc, request) {
9+
constructor(groupOptions, module, loc, request) {
1010
super();
11-
this.chunkName = name;
11+
if (typeof groupOptions === "string") {
12+
groupOptions = { name: groupOptions };
13+
} else if (!groupOptions) {
14+
groupOptions = { name: undefined };
15+
}
16+
this.groupOptions = groupOptions;
1217
this.chunkGroup = undefined;
1318
this.module = module;
1419
this.loc = loc;
1520
this.request = request;
1621
}
1722

23+
get chunkName() {
24+
return this.groupOptions.name;
25+
}
26+
27+
set chunkName(value) {
28+
this.groupOptions.name = value;
29+
}
30+
1831
get chunks() {
1932
throw new Error("Moved to AsyncDependenciesBlock.chunkGroup");
2033
}
@@ -24,7 +37,7 @@ module.exports = class AsyncDependenciesBlock extends DependenciesBlock {
2437
}
2538

2639
updateHash(hash) {
27-
hash.update(this.chunkName || "");
40+
hash.update(JSON.stringify(this.groupOptions));
2841
hash.update(
2942
(this.chunkGroup &&
3043
this.chunkGroup.chunks

lib/Chunk.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ class Chunk {
170170
if (aItem.done) return 0;
171171
const aModuleIdentifier = aItem.value.identifier();
172172
const bModuleIdentifier = bItem.value.identifier();
173-
if (aModuleIdentifier > bModuleIdentifier) return -1;
174-
if (aModuleIdentifier < bModuleIdentifier) return 1;
173+
if (aModuleIdentifier < bModuleIdentifier) return -1;
174+
if (aModuleIdentifier > bModuleIdentifier) return 1;
175175
}
176176
}
177177

@@ -361,6 +361,62 @@ class Chunk {
361361
};
362362
}
363363

364+
getChildIdsByOrders() {
365+
const lists = new Map();
366+
for (const group of this.groupsIterable) {
367+
if (group.chunks[group.chunks.length - 1] === this) {
368+
for (const childGroup of group.childrenIterable) {
369+
// TODO webpack 5 remove this check for options
370+
if (typeof childGroup.options === "object") {
371+
for (const key of Object.keys(childGroup.options)) {
372+
if (key.endsWith("Order")) {
373+
const name = key.substr(0, key.length - "Order".length);
374+
let list = lists.get(name);
375+
if (list === undefined) lists.set(name, (list = []));
376+
list.push({
377+
order: childGroup.options[key],
378+
group: childGroup
379+
});
380+
}
381+
}
382+
}
383+
}
384+
}
385+
}
386+
const result = Object.create(null);
387+
for (const [name, list] of lists) {
388+
list.sort((a, b) => {
389+
const cmp = b.order - a.order;
390+
if (cmp !== 0) return cmp;
391+
// TOOD webpack 5 remove this check of compareTo
392+
if (a.group.compareTo) return a.group.compareTo(b.group);
393+
return 0;
394+
});
395+
result[name] = Array.from(
396+
list.reduce((set, item) => {
397+
for (const chunk of item.group.chunks) set.add(chunk.id);
398+
return set;
399+
}, new Set())
400+
);
401+
}
402+
return result;
403+
}
404+
405+
getChildIdsByOrdersMap() {
406+
const chunkMaps = Object.create(null);
407+
408+
for (const chunk of this.getAllAsyncChunks()) {
409+
const data = chunk.getChildIdsByOrders();
410+
for (const key of Object.keys(data)) {
411+
let chunkMap = chunkMaps[key];
412+
if (chunkMap === undefined)
413+
chunkMaps[key] = chunkMap = Object.create(null);
414+
chunkMap[chunk.id] = data[key];
415+
}
416+
}
417+
return chunkMaps;
418+
}
419+
364420
getChunkModuleMaps(filterFn) {
365421
const chunkModuleIdMap = Object.create(null);
366422
const chunkModuleHashMap = Object.create(null);

lib/ChunkGroup.js

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,45 @@ const sortOrigin = (a, b) => {
2626
};
2727

2828
class ChunkGroup {
29-
constructor(name) {
29+
constructor(options) {
30+
if (typeof options === "string") {
31+
options = { name: options };
32+
} else if (!options) {
33+
options = { name: undefined };
34+
}
3035
this.groupDebugId = debugId++;
31-
this.name = name;
36+
this.options = options;
3237
this._children = new SortableSet(undefined, sortById);
3338
this._parents = new SortableSet(undefined, sortById);
3439
this._blocks = new SortableSet();
3540
this.chunks = [];
3641
this.origins = [];
3742
}
3843

44+
addOptions(options) {
45+
for (const key of Object.keys(options)) {
46+
if (this.options[key] === undefined) {
47+
this.options[key] = options[key];
48+
} else if (this.options[key] !== options[key]) {
49+
if (key.endsWith("Order")) {
50+
this.options[key] = Math.max(this.options[key], options[key]);
51+
} else {
52+
throw new Error(
53+
`ChunkGroup.addOptions: No option merge strategy for ${key}`
54+
);
55+
}
56+
}
57+
}
58+
}
59+
60+
get name() {
61+
return this.options.name;
62+
}
63+
64+
set name(value) {
65+
this.options.name = value;
66+
}
67+
3968
/* istanbul ignore next */
4069
get debugId() {
4170
return Array.from(this.chunks, x => x.debugId).join("+");
@@ -222,6 +251,18 @@ class ChunkGroup {
222251
return false;
223252
}
224253

254+
getFiles() {
255+
const files = new Set();
256+
257+
for (const chunk of this.chunks) {
258+
for (const file of chunk.files) {
259+
files.add(file);
260+
}
261+
}
262+
263+
return Array.from(files);
264+
}
265+
225266
remove(reason) {
226267
// cleanup parents
227268
for (const parentChunkGroup of this._parents) {
@@ -269,6 +310,53 @@ class ChunkGroup {
269310
this._children.sort();
270311
}
271312

313+
compareTo(otherGroup) {
314+
if (this.chunks.length > otherGroup.chunks.length) return -1;
315+
if (this.chunks.length < otherGroup.chunks.length) return 1;
316+
const a = this.chunks[Symbol.iterator]();
317+
const b = otherGroup.chunks[Symbol.iterator]();
318+
// eslint-disable-next-line
319+
while (true) {
320+
const aItem = a.next();
321+
const bItem = b.next();
322+
if (aItem.done) return 0;
323+
const cmp = aItem.value.compareTo(bItem.value);
324+
if (cmp !== 0) return cmp;
325+
}
326+
}
327+
328+
getChildrenByOrders() {
329+
const lists = new Map();
330+
for (const childGroup of this._children) {
331+
// TODO webpack 5 remove this check for options
332+
if (typeof childGroup.options === "object") {
333+
for (const key of Object.keys(childGroup.options)) {
334+
if (key.endsWith("Order")) {
335+
const name = key.substr(0, key.length - "Order".length);
336+
let list = lists.get(name);
337+
if (list === undefined) lists.set(name, (list = []));
338+
list.push({
339+
order: childGroup.options[key],
340+
group: childGroup
341+
});
342+
}
343+
}
344+
}
345+
}
346+
const result = Object.create(null);
347+
for (const [name, list] of lists) {
348+
list.sort((a, b) => {
349+
const cmp = b.order - a.order;
350+
if (cmp !== 0) return cmp;
351+
// TOOD webpack 5 remove this check of compareTo
352+
if (a.group.compareTo) return a.group.compareTo(b.group);
353+
return 0;
354+
});
355+
result[name] = list.map(i => i.group);
356+
}
357+
return result;
358+
}
359+
272360
checkConstraints() {
273361
const chunk = this;
274362
for (const child of chunk._children) {

lib/Compilation.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,17 +1006,22 @@ class Compilation extends Tapable {
10061006
}
10071007
}
10081008

1009-
addChunkInGroup(name, module, loc, request) {
1009+
addChunkInGroup(groupOptions, module, loc, request) {
1010+
if (typeof groupOptions === "string") {
1011+
groupOptions = { name: groupOptions };
1012+
}
1013+
const name = groupOptions.name;
10101014
if (name) {
10111015
const chunkGroup = this.namedChunkGroups.get(name);
10121016
if (chunkGroup !== undefined) {
1017+
chunkGroup.addOptions(groupOptions);
10131018
if (module) {
10141019
chunkGroup.addOrigin(module, loc, request);
10151020
}
10161021
return chunkGroup;
10171022
}
10181023
}
1019-
const chunkGroup = new ChunkGroup(name);
1024+
const chunkGroup = new ChunkGroup(groupOptions);
10201025
if (module) chunkGroup.addOrigin(module, loc, request);
10211026
const chunk = this.addChunk(name);
10221027

@@ -1190,11 +1195,18 @@ class Compilation extends Tapable {
11901195
);
11911196
c = chunkGroup;
11921197
} else {
1193-
c = this.addChunkInGroup(b.chunkName, module, b.loc, b.request);
1198+
c = this.addChunkInGroup(
1199+
b.groupOptions || b.chunkName,
1200+
module,
1201+
b.loc,
1202+
b.request
1203+
);
11941204
blockChunkGroups.set(b, c);
11951205
allCreatedChunkGroups.add(c);
11961206
}
11971207
} else {
1208+
// TODO webpack 5 remove addOptions check
1209+
if (c.addOptions) c.addOptions(b.groupOptions);
11981210
c.addOrigin(module, b.loc, b.request);
11991211
}
12001212

lib/ContextModule.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const Template = require("./Template");
1212

1313
class ContextModule extends Module {
1414
// type ContextMode = "sync" | "eager" | "weak" | "async-weak" | "lazy" | "lazy-once"
15-
// type ContextOptions = { resource: string, recursive: boolean, regExp: RegExp, addon?: string, mode?: ContextMode, chunkName?: string, include?: RegExp, exclude?: RegExp }
15+
// type ContextOptions = { resource: string, recursive: boolean, regExp: RegExp, addon?: string, mode?: ContextMode, chunkName?: string, include?: RegExp, exclude?: RegExp, groupOptions?: Object }
1616
// resolveDependencies: (fs: FS, options: ContextOptions, (err: Error?, dependencies: Dependency[]) => void) => void
1717
// options: ContextOptions
1818
constructor(resolveDependencies, options) {
@@ -81,6 +81,11 @@ class ContextModule extends Module {
8181
if (this.options.regExp) identifier += ` ${this.options.regExp}`;
8282
if (this.options.include) identifier += ` include: ${this.options.include}`;
8383
if (this.options.exclude) identifier += ` exclude: ${this.options.exclude}`;
84+
if (this.options.groupOptions) {
85+
identifier += ` groupOptions: ${JSON.stringify(
86+
this.options.groupOptions
87+
)}`;
88+
}
8489
if (this.options.namespaceObject === "strict")
8590
identifier += " strict namespace object";
8691
else if (this.options.namespaceObject) identifier += " namespace object";
@@ -106,6 +111,11 @@ class ContextModule extends Module {
106111
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
107112
if (this.options.exclude)
108113
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
114+
if (this.options.groupOptions) {
115+
const groupOptions = this.options.groupOptions;
116+
for (const key of Object.keys(groupOptions))
117+
identifier += ` ${key}: ${groupOptions[key]}`;
118+
}
109119
if (this.options.namespaceObject === "strict")
110120
identifier += " strict namespace object";
111121
else if (this.options.namespaceObject) identifier += " namespace object";
@@ -170,7 +180,9 @@ class ContextModule extends Module {
170180
// and add that block to this context
171181
if (dependencies.length > 0) {
172182
const block = new AsyncDependenciesBlock(
173-
this.options.chunkName,
183+
Object.assign({}, this.options.groupOptions, {
184+
name: this.options.chunkName
185+
}),
174186
this
175187
);
176188
for (const dep of dependencies) {
@@ -202,7 +214,9 @@ class ContextModule extends Module {
202214
);
203215
}
204216
const block = new AsyncDependenciesBlock(
205-
chunkName,
217+
Object.assign({}, this.options.groupOptions, {
218+
name: chunkName
219+
}),
206220
dep.module,
207221
dep.loc,
208222
dep.userRequest

lib/Entrypoint.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,6 @@ class Entrypoint extends ChunkGroup {
1616
return true;
1717
}
1818

19-
getFiles() {
20-
const files = new Set();
21-
22-
for (const chunk of this.chunks) {
23-
for (const file of chunk.files) {
24-
files.add(file);
25-
}
26-
}
27-
28-
return Array.from(files);
29-
}
30-
3119
setRuntimeChunk(chunk) {
3220
this.runtimeChunk = chunk;
3321
}

0 commit comments

Comments
 (0)