webpack 4.14.0 → 4.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/webpack.js +7 -2
- package/lib/AsyncDependenciesBlock.js +44 -0
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/Chunk.js +53 -3
- package/lib/ChunkGroup.js +1 -1
- package/lib/ChunkTemplate.js +14 -2
- package/lib/CommentCompilationWarning.js +2 -2
- package/lib/Compilation.js +435 -34
- package/lib/Compiler.js +57 -4
- package/lib/ContextModule.js +3 -15
- package/lib/DelegatedModule.js +9 -1
- package/lib/DependenciesBlock.js +36 -3
- package/lib/DependenciesBlockVariable.js +22 -0
- package/lib/Dependency.js +25 -4
- package/lib/DllEntryPlugin.js +4 -1
- package/lib/DynamicEntryPlugin.js +21 -1
- package/lib/EntryOptionPlugin.js +12 -0
- package/lib/ExtendedAPIPlugin.js +8 -4
- package/lib/ExternalModuleFactoryPlugin.js +1 -1
- package/lib/GraphHelpers.js +2 -1
- package/lib/HotModuleReplacement.runtime.js +8 -5
- package/lib/HotModuleReplacementPlugin.js +114 -116
- package/lib/MainTemplate.js +19 -4
- package/lib/Module.js +9 -3
- package/lib/ModuleReason.js +8 -0
- package/lib/MultiEntryPlugin.js +25 -3
- package/lib/NormalModule.js +5 -23
- package/lib/RuleSet.js +3 -3
- package/lib/SingleEntryPlugin.js +14 -0
- package/lib/Stats.js +2 -1
- package/lib/Template.js +4 -1
- package/lib/UmdMainTemplatePlugin.js +12 -12
- package/lib/WebpackError.js +4 -0
- package/lib/WebpackOptionsDefaulter.js +3 -0
- package/lib/WebpackOptionsValidationError.js +0 -1
- package/lib/compareLocations.js +13 -17
- package/lib/debug/ProfilingPlugin.js +5 -7
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +4 -6
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +0 -2
- package/lib/dependencies/LoaderDependency.js +3 -0
- package/lib/dependencies/LoaderPlugin.js +3 -1
- package/lib/dependencies/ModuleDependency.js +3 -0
- package/lib/dependencies/MultiEntryDependency.js +5 -0
- package/lib/dependencies/SingleEntryDependency.js +3 -0
- package/lib/node/NodeMainTemplateAsync.runtime.js +1 -1
- package/lib/optimize/ConcatenatedModule.js +1 -0
- package/lib/optimize/SplitChunksPlugin.js +142 -2
- package/lib/util/Semaphore.js +12 -0
- package/lib/util/SetHelpers.js +4 -4
- package/lib/util/SortableSet.js +1 -1
- package/lib/util/createHash.js +15 -0
- package/lib/util/deterministicGrouping.js +251 -0
- package/lib/util/identifier.js +27 -0
- package/lib/wasm/WasmMainTemplatePlugin.js +10 -4
- package/lib/wasm/WebAssemblyGenerator.js +12 -12
- package/lib/wasm/WebAssemblyInInitialChunkError.js +88 -0
- package/lib/wasm/WebAssemblyModulesPlugin.js +28 -0
- package/lib/webpack.web.js +2 -2
- package/package.json +8 -7
- package/schemas/WebpackOptions.json +37 -1
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Simulations show these probabilities for a single change
|
|
4
|
+
// 93.1% that one group is invalidated
|
|
5
|
+
// 4.8% that two groups are invalidated
|
|
6
|
+
// 1.1% that 3 groups are invalidated
|
|
7
|
+
// 0.1% that 4 or more groups are invalidated
|
|
8
|
+
//
|
|
9
|
+
// And these for removing/adding 10 lexically adjacent files
|
|
10
|
+
// 64.5% that one group is invalidated
|
|
11
|
+
// 24.8% that two groups are invalidated
|
|
12
|
+
// 7.8% that 3 groups are invalidated
|
|
13
|
+
// 2.7% that 4 or more groups are invalidated
|
|
14
|
+
//
|
|
15
|
+
// And these for removing/adding 3 random files
|
|
16
|
+
// 0% that one group is invalidated
|
|
17
|
+
// 3.7% that two groups are invalidated
|
|
18
|
+
// 80.8% that 3 groups are invalidated
|
|
19
|
+
// 12.3% that 4 groups are invalidated
|
|
20
|
+
// 3.2% that 5 or more groups are invalidated
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param {string} a key
|
|
25
|
+
* @param {string} b key
|
|
26
|
+
* @returns {number} the similarity as number
|
|
27
|
+
*/
|
|
28
|
+
const similarity = (a, b) => {
|
|
29
|
+
const l = Math.min(a.length, b.length);
|
|
30
|
+
let dist = 0;
|
|
31
|
+
for (let i = 0; i < l; i++) {
|
|
32
|
+
const ca = a.charCodeAt(i);
|
|
33
|
+
const cb = b.charCodeAt(i);
|
|
34
|
+
dist += Math.max(0, 10 - Math.abs(ca - cb));
|
|
35
|
+
}
|
|
36
|
+
return dist;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} a key
|
|
41
|
+
* @param {string} b key
|
|
42
|
+
* @returns {string} the common part and a single char for the difference
|
|
43
|
+
*/
|
|
44
|
+
const getName = (a, b) => {
|
|
45
|
+
const l = Math.min(a.length, b.length);
|
|
46
|
+
let r = "";
|
|
47
|
+
for (let i = 0; i < l; i++) {
|
|
48
|
+
const ca = a.charAt(i);
|
|
49
|
+
const cb = b.charAt(i);
|
|
50
|
+
r += ca;
|
|
51
|
+
if (ca === cb) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
return r;
|
|
55
|
+
}
|
|
56
|
+
return a;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @template T
|
|
61
|
+
*/
|
|
62
|
+
class Node {
|
|
63
|
+
/**
|
|
64
|
+
* @param {T} item item
|
|
65
|
+
* @param {string} key key
|
|
66
|
+
* @param {number} size size
|
|
67
|
+
*/
|
|
68
|
+
constructor(item, key, size) {
|
|
69
|
+
this.item = item;
|
|
70
|
+
this.key = key;
|
|
71
|
+
this.size = size;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @template T
|
|
77
|
+
*/
|
|
78
|
+
class Group {
|
|
79
|
+
/**
|
|
80
|
+
* @param {Node<T>[]} nodes nodes
|
|
81
|
+
* @param {number[]} similarities similarities between the nodes (length = nodes.length - 1)
|
|
82
|
+
*/
|
|
83
|
+
constructor(nodes, similarities) {
|
|
84
|
+
this.nodes = nodes;
|
|
85
|
+
this.similarities = similarities;
|
|
86
|
+
this.size = nodes.reduce((size, node) => size + node.size, 0);
|
|
87
|
+
/** @type {string} */
|
|
88
|
+
this.key = undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @template T
|
|
94
|
+
* @typedef {Object} GroupedItems<T>
|
|
95
|
+
* @property {string} key
|
|
96
|
+
* @property {T[]} items
|
|
97
|
+
* @property {number} size
|
|
98
|
+
*/
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @template T
|
|
102
|
+
* @typedef {Object} Options
|
|
103
|
+
* @property {number} maxSize maximum size of a group
|
|
104
|
+
* @property {number} minSize minimum size of a group (preferred over maximum size)
|
|
105
|
+
* @property {Iterable<T>} items a list of items
|
|
106
|
+
* @property {function(T): number} getSize function to get size of an item
|
|
107
|
+
* @property {function(T): string} getKey function to get the key of an item
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @template T
|
|
112
|
+
* @param {Options<T>} options options object
|
|
113
|
+
* @returns {GroupedItems<T>[]} grouped items
|
|
114
|
+
*/
|
|
115
|
+
module.exports = ({ maxSize, minSize, items, getSize, getKey }) => {
|
|
116
|
+
/** @type {Group<T>[]} */
|
|
117
|
+
const result = [];
|
|
118
|
+
|
|
119
|
+
const nodes = Array.from(
|
|
120
|
+
items,
|
|
121
|
+
item => new Node(item, getKey(item), getSize(item))
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
/** @type {Node<T>[]} */
|
|
125
|
+
const initialNodes = [];
|
|
126
|
+
|
|
127
|
+
// return nodes bigger than maxSize directly as group
|
|
128
|
+
for (const node of nodes) {
|
|
129
|
+
if (node.size >= maxSize) {
|
|
130
|
+
result.push(new Group([node], []));
|
|
131
|
+
} else {
|
|
132
|
+
initialNodes.push(node);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (initialNodes.length > 0) {
|
|
137
|
+
// lexically ordering of keys
|
|
138
|
+
initialNodes.sort((a, b) => {
|
|
139
|
+
if (a.key < b.key) return -1;
|
|
140
|
+
if (a.key > b.key) return 1;
|
|
141
|
+
return 0;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// calculate similarities between lexically adjacent nodes
|
|
145
|
+
/** @type {number[]} */
|
|
146
|
+
const similarities = [];
|
|
147
|
+
for (let i = 1; i < initialNodes.length; i++) {
|
|
148
|
+
const a = initialNodes[i - 1];
|
|
149
|
+
const b = initialNodes[i];
|
|
150
|
+
similarities.push(similarity(a.key, b.key));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const queue = [new Group(initialNodes, similarities)];
|
|
154
|
+
|
|
155
|
+
while (queue.length) {
|
|
156
|
+
const group = queue.pop();
|
|
157
|
+
// only groups bigger than maxSize need to be splitted
|
|
158
|
+
if (group.size < maxSize) {
|
|
159
|
+
result.push(group);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// find unsplittable area from left and right
|
|
164
|
+
// going minSize from left and right
|
|
165
|
+
let left = 0;
|
|
166
|
+
let leftSize = 0;
|
|
167
|
+
while (leftSize < minSize) {
|
|
168
|
+
leftSize += group.nodes[left].size;
|
|
169
|
+
left++;
|
|
170
|
+
}
|
|
171
|
+
let right = group.nodes.length - 1;
|
|
172
|
+
let rightSize = 0;
|
|
173
|
+
while (rightSize < minSize) {
|
|
174
|
+
rightSize += group.nodes[right].size;
|
|
175
|
+
right--;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (left - 1 > right) {
|
|
179
|
+
// can't split group while holding minSize
|
|
180
|
+
// because minSize is preferred of maxSize we return
|
|
181
|
+
// the group here even while it's too big
|
|
182
|
+
// To avoid this make sure maxSize > minSize * 3
|
|
183
|
+
result.push(group);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (left <= right) {
|
|
187
|
+
// when there is a area between left and right
|
|
188
|
+
// we look for best split point
|
|
189
|
+
// we split at the minimum similiarity
|
|
190
|
+
// here key space is separated the most
|
|
191
|
+
let best = left - 1;
|
|
192
|
+
let bestSimilarity = group.similarities[best];
|
|
193
|
+
for (let i = left; i <= right; i++) {
|
|
194
|
+
const similarity = group.similarities[i];
|
|
195
|
+
if (similarity < bestSimilarity) {
|
|
196
|
+
best = i;
|
|
197
|
+
bestSimilarity = similarity;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
left = best + 1;
|
|
201
|
+
right = best;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// create two new groups for left and right area
|
|
205
|
+
// and queue them up
|
|
206
|
+
const rightNodes = [group.nodes[right + 1]];
|
|
207
|
+
/** @type {number[]} */
|
|
208
|
+
const rightSimilaries = [];
|
|
209
|
+
for (let i = right + 2; i < group.nodes.length; i++) {
|
|
210
|
+
rightSimilaries.push(group.similarities[i - 1]);
|
|
211
|
+
rightNodes.push(group.nodes[i]);
|
|
212
|
+
}
|
|
213
|
+
queue.push(new Group(rightNodes, rightSimilaries));
|
|
214
|
+
|
|
215
|
+
const leftNodes = [group.nodes[0]];
|
|
216
|
+
/** @type {number[]} */
|
|
217
|
+
const leftSimilaries = [];
|
|
218
|
+
for (let i = 1; i < left; i++) {
|
|
219
|
+
leftSimilaries.push(group.similarities[i - 1]);
|
|
220
|
+
leftNodes.push(group.nodes[i]);
|
|
221
|
+
}
|
|
222
|
+
queue.push(new Group(leftNodes, leftSimilaries));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// lexically ordering
|
|
227
|
+
result.sort((a, b) => {
|
|
228
|
+
if (a.nodes[0].key < b.nodes[0].key) return -1;
|
|
229
|
+
if (a.nodes[0].key > b.nodes[0].key) return 1;
|
|
230
|
+
return 0;
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// give every group a name
|
|
234
|
+
for (let i = 0; i < result.length; i++) {
|
|
235
|
+
const group = result[i];
|
|
236
|
+
const first = group.nodes[0];
|
|
237
|
+
const last = group.nodes[group.nodes.length - 1];
|
|
238
|
+
let name = getName(first.key, last.key);
|
|
239
|
+
group.key = name;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// return the results
|
|
243
|
+
return result.map(group => {
|
|
244
|
+
/** @type {GroupedItems} */
|
|
245
|
+
return {
|
|
246
|
+
key: group.key,
|
|
247
|
+
items: group.nodes.map(node => node.item),
|
|
248
|
+
size: group.size
|
|
249
|
+
};
|
|
250
|
+
});
|
|
251
|
+
};
|
package/lib/util/identifier.js
CHANGED
|
@@ -74,3 +74,30 @@ exports.makePathsRelative = (context, identifier, cache) => {
|
|
|
74
74
|
return relativePath;
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @param {string} context absolute context path
|
|
80
|
+
* @param {string} request any request string may containing absolute paths, query string, etc.
|
|
81
|
+
* @returns {string} a new request string avoiding absolute paths when possible
|
|
82
|
+
*/
|
|
83
|
+
exports.contextify = (context, request) => {
|
|
84
|
+
return request
|
|
85
|
+
.split("!")
|
|
86
|
+
.map(r => {
|
|
87
|
+
const splitPath = r.split("?", 2);
|
|
88
|
+
if (/^[a-zA-Z]:\\/.test(splitPath[0])) {
|
|
89
|
+
splitPath[0] = path.win32.relative(context, splitPath[0]);
|
|
90
|
+
if (!/^[a-zA-Z]:\\/.test(splitPath[0])) {
|
|
91
|
+
splitPath[0] = splitPath[0].replace(/\\/g, "/");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (/^\//.test(splitPath[0])) {
|
|
95
|
+
splitPath[0] = path.posix.relative(context, splitPath[0]);
|
|
96
|
+
}
|
|
97
|
+
if (!/^(\.\.\/|\/|[a-zA-Z]:\\)/.test(splitPath[0])) {
|
|
98
|
+
splitPath[0] = "./" + splitPath[0];
|
|
99
|
+
}
|
|
100
|
+
return splitPath.join("?");
|
|
101
|
+
})
|
|
102
|
+
.join("!");
|
|
103
|
+
};
|
|
@@ -8,9 +8,10 @@ const Template = require("../Template");
|
|
|
8
8
|
const WebAssemblyUtils = require("./WebAssemblyUtils");
|
|
9
9
|
|
|
10
10
|
/** @typedef {import("../Module")} Module */
|
|
11
|
+
/** @typedef {import("../MainTemplate")} MainTemplate */
|
|
11
12
|
|
|
12
13
|
// Get all wasm modules
|
|
13
|
-
|
|
14
|
+
const getAllWasmModules = chunk => {
|
|
14
15
|
const wasmModules = chunk.getAllAsyncChunks();
|
|
15
16
|
const array = [];
|
|
16
17
|
for (const chunk of wasmModules) {
|
|
@@ -22,7 +23,7 @@ function getAllWasmModules(chunk) {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
return array;
|
|
25
|
-
}
|
|
26
|
+
};
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* generates the import object function for a module
|
|
@@ -30,7 +31,7 @@ function getAllWasmModules(chunk) {
|
|
|
30
31
|
* @param {boolean} mangle mangle imports
|
|
31
32
|
* @returns {string} source code
|
|
32
33
|
*/
|
|
33
|
-
|
|
34
|
+
const generateImportObject = (module, mangle) => {
|
|
34
35
|
const waitForInstances = new Map();
|
|
35
36
|
const properties = [];
|
|
36
37
|
const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies(
|
|
@@ -151,7 +152,7 @@ function generateImportObject(module, mangle) {
|
|
|
151
152
|
"},"
|
|
152
153
|
]);
|
|
153
154
|
}
|
|
154
|
-
}
|
|
155
|
+
};
|
|
155
156
|
|
|
156
157
|
class WasmMainTemplatePlugin {
|
|
157
158
|
constructor({ generateLoadBinaryCode, supportsStreaming, mangleImports }) {
|
|
@@ -159,6 +160,11 @@ class WasmMainTemplatePlugin {
|
|
|
159
160
|
this.supportsStreaming = supportsStreaming;
|
|
160
161
|
this.mangleImports = mangleImports;
|
|
161
162
|
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @param {MainTemplate} mainTemplate main template
|
|
166
|
+
* @returns {void}
|
|
167
|
+
*/
|
|
162
168
|
apply(mainTemplate) {
|
|
163
169
|
mainTemplate.hooks.localVars.tap(
|
|
164
170
|
"WasmMainTemplatePlugin",
|
|
@@ -32,21 +32,21 @@ const WebAssemblyExportImportedDependency = require("../dependencies/WebAssembly
|
|
|
32
32
|
* @param {ArrayBuffer} ab - original binary
|
|
33
33
|
* @returns {ArrayBufferTransform} transform
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
const preprocess = ab => {
|
|
36
36
|
const optBin = shrinkPaddedLEB128(new Uint8Array(ab));
|
|
37
37
|
return optBin.buffer;
|
|
38
|
-
}
|
|
38
|
+
};
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* @template T
|
|
42
42
|
* @param {Function[]} fns transforms
|
|
43
43
|
* @returns {Function} composed transform
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
const compose = (...fns) => {
|
|
46
46
|
return fns.reduce((prevFn, nextFn) => {
|
|
47
47
|
return value => nextFn(prevFn(value));
|
|
48
48
|
}, value => value);
|
|
49
|
-
}
|
|
49
|
+
};
|
|
50
50
|
|
|
51
51
|
// TODO replace with @callback
|
|
52
52
|
|
|
@@ -70,7 +70,7 @@ const removeStartFunc = state => bin => {
|
|
|
70
70
|
* @param {Object} ast - Module's AST
|
|
71
71
|
* @returns {Array<t.ModuleImport>} - nodes
|
|
72
72
|
*/
|
|
73
|
-
|
|
73
|
+
const getImportedGlobals = ast => {
|
|
74
74
|
const importedGlobals = [];
|
|
75
75
|
|
|
76
76
|
t.traverse(ast, {
|
|
@@ -82,9 +82,9 @@ function getImportedGlobals(ast) {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
return importedGlobals;
|
|
85
|
-
}
|
|
85
|
+
};
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
const getCountImportedFunc = ast => {
|
|
88
88
|
let count = 0;
|
|
89
89
|
|
|
90
90
|
t.traverse(ast, {
|
|
@@ -96,7 +96,7 @@ function getCountImportedFunc(ast) {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
return count;
|
|
99
|
-
}
|
|
99
|
+
};
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Get next type index
|
|
@@ -104,7 +104,7 @@ function getCountImportedFunc(ast) {
|
|
|
104
104
|
* @param {Object} ast - Module's AST
|
|
105
105
|
* @returns {t.Index} - index
|
|
106
106
|
*/
|
|
107
|
-
|
|
107
|
+
const getNextTypeIndex = ast => {
|
|
108
108
|
const typeSectionMetadata = t.getSectionMetadata(ast, "type");
|
|
109
109
|
|
|
110
110
|
if (typeof typeSectionMetadata === "undefined") {
|
|
@@ -112,7 +112,7 @@ function getNextTypeIndex(ast) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
return t.indexLiteral(typeSectionMetadata.vectorOfSize.value);
|
|
115
|
-
}
|
|
115
|
+
};
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
118
|
* Get next func index
|
|
@@ -125,7 +125,7 @@ function getNextTypeIndex(ast) {
|
|
|
125
125
|
* @param {Number} countImportedFunc - number of imported funcs
|
|
126
126
|
* @returns {t.Index} - index
|
|
127
127
|
*/
|
|
128
|
-
|
|
128
|
+
const getNextFuncIndex = (ast, countImportedFunc) => {
|
|
129
129
|
const funcSectionMetadata = t.getSectionMetadata(ast, "func");
|
|
130
130
|
|
|
131
131
|
if (typeof funcSectionMetadata === "undefined") {
|
|
@@ -135,7 +135,7 @@ function getNextFuncIndex(ast, countImportedFunc) {
|
|
|
135
135
|
const vectorOfSize = funcSectionMetadata.vectorOfSize.value;
|
|
136
136
|
|
|
137
137
|
return t.indexLiteral(vectorOfSize + countImportedFunc);
|
|
138
|
-
}
|
|
138
|
+
};
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* Create a init instruction for a global
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const WebpackError = require("../WebpackError");
|
|
7
|
+
|
|
8
|
+
/** @typedef {import("../Module")} Module */
|
|
9
|
+
/** @typedef {import("../RequestShortener")} RequestShortener */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Module} module module to get chains from
|
|
13
|
+
* @param {RequestShortener} requestShortener to make readable identifiers
|
|
14
|
+
* @returns {string[]} all chains to the module
|
|
15
|
+
*/
|
|
16
|
+
const getInitialModuleChains = (module, requestShortener) => {
|
|
17
|
+
const queue = [
|
|
18
|
+
{ head: module, message: module.readableIdentifier(requestShortener) }
|
|
19
|
+
];
|
|
20
|
+
/** @type {Set<string>} */
|
|
21
|
+
const results = new Set();
|
|
22
|
+
/** @type {Set<string>} */
|
|
23
|
+
const incompleteResults = new Set();
|
|
24
|
+
/** @type {Set<Module>} */
|
|
25
|
+
const visitedModules = new Set();
|
|
26
|
+
|
|
27
|
+
for (const chain of queue) {
|
|
28
|
+
const { head, message } = chain;
|
|
29
|
+
let final = true;
|
|
30
|
+
/** @type {Set<Module>} */
|
|
31
|
+
const alreadyReferencedModules = new Set();
|
|
32
|
+
for (const reason of head.reasons) {
|
|
33
|
+
const newHead = reason.module;
|
|
34
|
+
if (newHead) {
|
|
35
|
+
if (!newHead.getChunks().some(c => c.canBeInitial())) continue;
|
|
36
|
+
final = false;
|
|
37
|
+
if (alreadyReferencedModules.has(newHead)) continue;
|
|
38
|
+
alreadyReferencedModules.add(newHead);
|
|
39
|
+
const moduleName = newHead.readableIdentifier(requestShortener);
|
|
40
|
+
const detail = reason.explanation ? ` (${reason.explanation})` : "";
|
|
41
|
+
const newMessage = `${moduleName}${detail} --> ${message}`;
|
|
42
|
+
if (visitedModules.has(newHead)) {
|
|
43
|
+
incompleteResults.add(`... --> ${newMessage}`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
visitedModules.add(newHead);
|
|
47
|
+
queue.push({
|
|
48
|
+
head: newHead,
|
|
49
|
+
message: newMessage
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
final = false;
|
|
53
|
+
const newMessage = reason.explanation
|
|
54
|
+
? `(${reason.explanation}) --> ${message}`
|
|
55
|
+
: message;
|
|
56
|
+
results.add(newMessage);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (final) {
|
|
60
|
+
results.add(message);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const result of incompleteResults) {
|
|
64
|
+
results.add(result);
|
|
65
|
+
}
|
|
66
|
+
return Array.from(results);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
module.exports = class WebAssemblyInInitialChunkError extends WebpackError {
|
|
70
|
+
/**
|
|
71
|
+
* @param {Module} module WASM module
|
|
72
|
+
* @param {RequestShortener} requestShortener request shortener
|
|
73
|
+
*/
|
|
74
|
+
constructor(module, requestShortener) {
|
|
75
|
+
const moduleChains = getInitialModuleChains(module, requestShortener);
|
|
76
|
+
const message = `WebAssembly module is included in initial chunk.
|
|
77
|
+
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
|
|
78
|
+
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
|
|
79
|
+
${moduleChains.map(s => `* ${s}`).join("\n")}`;
|
|
80
|
+
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "WebAssemblyInInitialChunkError";
|
|
83
|
+
this.hideStack = true;
|
|
84
|
+
this.module = module;
|
|
85
|
+
|
|
86
|
+
Error.captureStackTrace(this, this.constructor);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
@@ -10,12 +10,19 @@ const WebAssemblyGenerator = require("./WebAssemblyGenerator");
|
|
|
10
10
|
const WebAssemblyJavascriptGenerator = require("./WebAssemblyJavascriptGenerator");
|
|
11
11
|
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
|
|
12
12
|
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
|
|
13
|
+
const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");
|
|
14
|
+
|
|
15
|
+
/** @typedef {import("../Compiler")} Compiler */
|
|
13
16
|
|
|
14
17
|
class WebAssemblyModulesPlugin {
|
|
15
18
|
constructor(options) {
|
|
16
19
|
this.options = options;
|
|
17
20
|
}
|
|
18
21
|
|
|
22
|
+
/**
|
|
23
|
+
* @param {Compiler} compiler compiler
|
|
24
|
+
* @returns {void}
|
|
25
|
+
*/
|
|
19
26
|
apply(compiler) {
|
|
20
27
|
compiler.hooks.compilation.tap(
|
|
21
28
|
"WebAssemblyModulesPlugin",
|
|
@@ -78,6 +85,27 @@ class WebAssemblyModulesPlugin {
|
|
|
78
85
|
return result;
|
|
79
86
|
}
|
|
80
87
|
);
|
|
88
|
+
|
|
89
|
+
compilation.hooks.afterChunks.tap("WebAssemblyModulesPlugin", () => {
|
|
90
|
+
const initialWasmModules = new Set();
|
|
91
|
+
for (const chunk of compilation.chunks) {
|
|
92
|
+
if (chunk.canBeInitial()) {
|
|
93
|
+
for (const module of chunk.modulesIterable) {
|
|
94
|
+
if (module.type.startsWith("webassembly")) {
|
|
95
|
+
initialWasmModules.add(module);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
for (const module of initialWasmModules) {
|
|
101
|
+
compilation.errors.push(
|
|
102
|
+
new WebAssemblyInInitialChunkError(
|
|
103
|
+
module,
|
|
104
|
+
compilation.requestShortener
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
81
109
|
}
|
|
82
110
|
);
|
|
83
111
|
}
|
package/lib/webpack.web.js
CHANGED
|
@@ -9,7 +9,7 @@ const WebEnvironmentPlugin = require("./web/WebEnvironmentPlugin");
|
|
|
9
9
|
const WebpackOptionsApply = require("./WebpackOptionsApply");
|
|
10
10
|
const WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter");
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const webpack = (options, callback) => {
|
|
13
13
|
new WebpackOptionsDefaulter().process(options);
|
|
14
14
|
|
|
15
15
|
const compiler = new Compiler();
|
|
@@ -22,7 +22,7 @@ function webpack(options, callback) {
|
|
|
22
22
|
compiler.run(callback);
|
|
23
23
|
}
|
|
24
24
|
return compiler;
|
|
25
|
-
}
|
|
25
|
+
};
|
|
26
26
|
module.exports = webpack;
|
|
27
27
|
|
|
28
28
|
webpack.WebpackOptionsDefaulter = WebpackOptionsDefaulter;
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webpack",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.15.1",
|
|
4
4
|
"author": "Tobias Koppers @sokra",
|
|
5
5
|
"description": "Packs CommonJs/AMD modules for the browser. Allows to split your codebase into multiple bundles, which can be loaded on demand. Support loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@webassemblyjs/ast": "1.5.
|
|
9
|
-
"@webassemblyjs/helper-module-context": "1.5.
|
|
10
|
-
"@webassemblyjs/wasm-edit": "1.5.
|
|
11
|
-
"@webassemblyjs/wasm-opt": "1.5.
|
|
12
|
-
"@webassemblyjs/wasm-parser": "1.5.
|
|
8
|
+
"@webassemblyjs/ast": "1.5.13",
|
|
9
|
+
"@webassemblyjs/helper-module-context": "1.5.13",
|
|
10
|
+
"@webassemblyjs/wasm-edit": "1.5.13",
|
|
11
|
+
"@webassemblyjs/wasm-opt": "1.5.13",
|
|
12
|
+
"@webassemblyjs/wasm-parser": "1.5.13",
|
|
13
13
|
"acorn": "^5.6.2",
|
|
14
14
|
"acorn-dynamic-import": "^3.0.0",
|
|
15
15
|
"ajv": "^6.1.0",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^9.6.4",
|
|
36
36
|
"@types/tapable": "^1.0.1",
|
|
37
|
+
"@types/webpack-sources": "^0.1.4",
|
|
37
38
|
"benchmark": "^2.1.1",
|
|
38
39
|
"bundle-loader": "~0.5.0",
|
|
39
40
|
"codacy-coverage": "^2.0.1",
|
|
@@ -122,7 +123,7 @@
|
|
|
122
123
|
"code-lint": "eslint --cache setup lib bin hot buildin benchmark \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\"",
|
|
123
124
|
"type-lint": "tsc --pretty",
|
|
124
125
|
"fix": "yarn code-lint --fix",
|
|
125
|
-
"pretty": "prettier --write \"setup/**/*.js\" \"lib/**/*.js\" \"bin/*.js\" \"hot/*.js\" \"buildin/*.js\" \"benchmark/**/*.js\" \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\" \"declarations.d.ts\"",
|
|
126
|
+
"pretty": "prettier --write \"setup/**/*.js\" \"lib/**/*.js\" \"bin/*.js\" \"hot/*.js\" \"buildin/*.js\" \"benchmark/**/*.js\" \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\" \"declarations.d.ts\" \"tsconfig.json\"",
|
|
126
127
|
"schema-lint": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.lint.js\" --no-verbose",
|
|
127
128
|
"benchmark": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.benchmark.js\" --runInBand",
|
|
128
129
|
"cover": "yarn cover:init && yarn cover:all && yarn cover:report",
|
|
@@ -1351,7 +1351,12 @@
|
|
|
1351
1351
|
]
|
|
1352
1352
|
},
|
|
1353
1353
|
"minSize": {
|
|
1354
|
-
"description": "Minimal size for the created
|
|
1354
|
+
"description": "Minimal size for the created chunks",
|
|
1355
|
+
"type": "number",
|
|
1356
|
+
"minimum": 0
|
|
1357
|
+
},
|
|
1358
|
+
"maxSize": {
|
|
1359
|
+
"description": "Maximal size hint for the created chunks",
|
|
1355
1360
|
"type": "number",
|
|
1356
1361
|
"minimum": 0
|
|
1357
1362
|
},
|
|
@@ -1394,6 +1399,32 @@
|
|
|
1394
1399
|
"type": "string",
|
|
1395
1400
|
"minLength": 1
|
|
1396
1401
|
},
|
|
1402
|
+
"hidePathInfo": {
|
|
1403
|
+
"description": "Prevents exposing path info when creating names for parts splitted by maxSize",
|
|
1404
|
+
"type": "boolean"
|
|
1405
|
+
},
|
|
1406
|
+
"fallbackCacheGroup": {
|
|
1407
|
+
"description": "Options for modules not selected by any other cache group",
|
|
1408
|
+
"type": "object",
|
|
1409
|
+
"additionalProperties": false,
|
|
1410
|
+
"properties": {
|
|
1411
|
+
"minSize": {
|
|
1412
|
+
"description": "Minimal size for the created chunk",
|
|
1413
|
+
"type": "number",
|
|
1414
|
+
"minimum": 0
|
|
1415
|
+
},
|
|
1416
|
+
"maxSize": {
|
|
1417
|
+
"description": "Maximal size hint for the created chunks",
|
|
1418
|
+
"type": "number",
|
|
1419
|
+
"minimum": 0
|
|
1420
|
+
},
|
|
1421
|
+
"automaticNameDelimiter": {
|
|
1422
|
+
"description": "Sets the name delimiter for created chunks",
|
|
1423
|
+
"type": "string",
|
|
1424
|
+
"minLength": 1
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1397
1428
|
"cacheGroups": {
|
|
1398
1429
|
"description": "Assign modules to a cache group (modules from different cache groups are tried to keep in separate chunks)",
|
|
1399
1430
|
"type": "object",
|
|
@@ -1460,6 +1491,11 @@
|
|
|
1460
1491
|
"type": "number",
|
|
1461
1492
|
"minimum": 0
|
|
1462
1493
|
},
|
|
1494
|
+
"maxSize": {
|
|
1495
|
+
"description": "Maximal size hint for the created chunks",
|
|
1496
|
+
"type": "number",
|
|
1497
|
+
"minimum": 0
|
|
1498
|
+
},
|
|
1463
1499
|
"minChunks": {
|
|
1464
1500
|
"description": "Minimum number of times a module has to be duplicated until it's considered for splitting",
|
|
1465
1501
|
"type": "number",
|