webpack 4.14.0 → 4.16.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.
Files changed (111) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +5 -2
  3. package/bin/webpack.js +7 -2
  4. package/buildin/amd-define.js +3 -3
  5. package/buildin/amd-options.js +2 -2
  6. package/buildin/system.js +7 -7
  7. package/hot/dev-server.js +2 -2
  8. package/hot/emitter.js +2 -2
  9. package/hot/only-dev-server.js +2 -2
  10. package/hot/poll.js +5 -2
  11. package/hot/signal.js +2 -2
  12. package/lib/AsyncDependenciesBlock.js +44 -0
  13. package/lib/AutomaticPrefetchPlugin.js +2 -2
  14. package/lib/Chunk.js +56 -6
  15. package/lib/ChunkGroup.js +2 -2
  16. package/lib/ChunkTemplate.js +14 -2
  17. package/lib/CommentCompilationWarning.js +3 -3
  18. package/lib/CompatibilityPlugin.js +1 -1
  19. package/lib/Compilation.js +442 -37
  20. package/lib/Compiler.js +57 -4
  21. package/lib/ContextModule.js +23 -16
  22. package/lib/DefinePlugin.js +49 -0
  23. package/lib/DelegatedModule.js +9 -1
  24. package/lib/DelegatedModuleFactoryPlugin.js +7 -1
  25. package/lib/DependenciesBlock.js +36 -3
  26. package/lib/DependenciesBlockVariable.js +22 -0
  27. package/lib/Dependency.js +33 -6
  28. package/lib/DllEntryPlugin.js +4 -1
  29. package/lib/DynamicEntryPlugin.js +21 -1
  30. package/lib/EntryOptionPlugin.js +12 -0
  31. package/lib/Entrypoint.js +1 -1
  32. package/lib/EnvironmentPlugin.js +8 -1
  33. package/lib/ExtendedAPIPlugin.js +8 -4
  34. package/lib/ExternalModuleFactoryPlugin.js +1 -1
  35. package/lib/Generator.js +1 -1
  36. package/lib/GraphHelpers.js +2 -1
  37. package/lib/HotModuleReplacement.runtime.js +8 -5
  38. package/lib/HotModuleReplacementPlugin.js +115 -117
  39. package/lib/IgnorePlugin.js +1 -1
  40. package/lib/MainTemplate.js +19 -4
  41. package/lib/MemoryOutputFileSystem.js +5 -5
  42. package/lib/Module.js +9 -3
  43. package/lib/ModuleReason.js +8 -0
  44. package/lib/MultiEntryPlugin.js +25 -3
  45. package/lib/NormalModule.js +5 -23
  46. package/lib/NullFactory.js +12 -12
  47. package/lib/OptionsApply.js +10 -10
  48. package/lib/RuleSet.js +3 -3
  49. package/lib/SingleEntryPlugin.js +20 -1
  50. package/lib/Stats.js +12 -5
  51. package/lib/Template.js +4 -1
  52. package/lib/UmdMainTemplatePlugin.js +12 -12
  53. package/lib/UseStrictPlugin.js +1 -1
  54. package/lib/WebpackError.js +4 -0
  55. package/lib/WebpackOptionsApply.js +92 -10
  56. package/lib/WebpackOptionsDefaulter.js +23 -6
  57. package/lib/WebpackOptionsValidationError.js +0 -1
  58. package/lib/compareLocations.js +13 -17
  59. package/lib/debug/ProfilingPlugin.js +5 -7
  60. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +4 -6
  61. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +0 -2
  62. package/lib/dependencies/AMDRequireItemDependency.js +22 -22
  63. package/lib/dependencies/CommonJsRequireDependency.js +22 -22
  64. package/lib/dependencies/CriticalDependencyWarning.js +20 -20
  65. package/lib/dependencies/DelegatedSourceDependency.js +18 -18
  66. package/lib/dependencies/DllEntryDependency.js +20 -20
  67. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +2 -1
  68. package/lib/dependencies/LoaderDependency.js +3 -0
  69. package/lib/dependencies/LoaderPlugin.js +21 -2
  70. package/lib/dependencies/LocalModule.js +23 -23
  71. package/lib/dependencies/ModuleDependency.js +3 -0
  72. package/lib/dependencies/ModuleHotAcceptDependency.js +23 -23
  73. package/lib/dependencies/ModuleHotDeclineDependency.js +23 -23
  74. package/lib/dependencies/MultiEntryDependency.js +5 -0
  75. package/lib/dependencies/PrefetchDependency.js +18 -18
  76. package/lib/dependencies/RequireEnsureItemDependency.js +21 -21
  77. package/lib/dependencies/RequireResolveDependency.js +22 -22
  78. package/lib/dependencies/SingleEntryDependency.js +3 -0
  79. package/lib/dependencies/SystemPlugin.js +1 -1
  80. package/lib/formatLocation.js +55 -41
  81. package/lib/node/NodeMainTemplateAsync.runtime.js +1 -1
  82. package/lib/node/NodeMainTemplatePlugin.js +2 -2
  83. package/lib/node/NodeOutputFileSystem.js +22 -22
  84. package/lib/node/NodeSourcePlugin.js +1 -1
  85. package/lib/optimize/ConcatenatedModule.js +1 -0
  86. package/lib/optimize/NaturalChunkOrderPlugin.js +41 -0
  87. package/lib/optimize/OccurrenceChunkOrderPlugin.js +61 -0
  88. package/lib/optimize/OccurrenceModuleOrderPlugin.js +103 -0
  89. package/lib/optimize/OccurrenceOrderPlugin.js +4 -2
  90. package/lib/optimize/SplitChunksPlugin.js +168 -18
  91. package/lib/util/Semaphore.js +12 -0
  92. package/lib/util/SetHelpers.js +4 -4
  93. package/lib/util/SortableSet.js +1 -1
  94. package/lib/util/cachedMerge.js +1 -1
  95. package/lib/util/createHash.js +15 -0
  96. package/lib/util/deterministicGrouping.js +251 -0
  97. package/lib/util/identifier.js +27 -0
  98. package/lib/wasm/WasmFinalizeExportsPlugin.js +1 -1
  99. package/lib/wasm/WasmMainTemplatePlugin.js +10 -4
  100. package/lib/wasm/WebAssemblyGenerator.js +12 -12
  101. package/lib/wasm/WebAssemblyInInitialChunkError.js +88 -0
  102. package/lib/wasm/WebAssemblyModulesPlugin.js +28 -0
  103. package/lib/web/JsonpMainTemplatePlugin.js +1 -1
  104. package/lib/web/WebEnvironmentPlugin.js +18 -18
  105. package/lib/webpack.js +4 -0
  106. package/lib/webpack.web.js +2 -2
  107. package/lib/webworker/WebWorkerMainTemplatePlugin.js +1 -1
  108. package/package.json +27 -17
  109. package/schemas/WebpackOptions.json +71 -9
  110. package/schemas/plugins/optimize/OccurrenceOrderChunkIdsPlugin.json +10 -0
  111. package/schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json +10 -0
@@ -7,7 +7,7 @@
7
7
  const mergeCache = new WeakMap();
8
8
 
9
9
  /**
10
- * Merges two given objects and caches the result to avoid computation if same objects passed as arguements again.
10
+ * Merges two given objects and caches the result to avoid computation if same objects passed as arguments again.
11
11
  * @example
12
12
  * // performs Object.assign(first, second), stores the result in WeakMap and returns result
13
13
  * cachedMerge({a: 1}, {a: 2})
@@ -4,8 +4,18 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ /** @typedef {{new(): Hash}} HashConstructor */
8
+ /**
9
+ * @typedef {Object} Hash
10
+ * @property {function(string|Buffer, string=): Hash} update
11
+ * @property {function(string): string} digest
12
+ */
13
+
7
14
  const BULK_SIZE = 1000;
8
15
 
16
+ /**
17
+ * @implements {Hash}
18
+ */
9
19
  class BulkUpdateDecorator {
10
20
  constructor(hash) {
11
21
  this.hash = hash;
@@ -63,6 +73,11 @@ class DebugHash {
63
73
  }
64
74
  }
65
75
 
76
+ /**
77
+ * Creates a hash by name or function
78
+ * @param {string | HashConstructor} algorithm the algorithm name or a constructor creating a hash
79
+ * @returns {Hash} the hash
80
+ */
66
81
  module.exports = algorithm => {
67
82
  if (typeof algorithm === "function") {
68
83
  return new BulkUpdateDecorator(new algorithm());
@@ -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 similarity
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
+ };
@@ -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
+ };
@@ -4,7 +4,7 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
- const UnsupportedWebAssemblyFeatureError = require("../wasm/UnsupportedWebAssemblyFeatureError");
7
+ const UnsupportedWebAssemblyFeatureError = require("./UnsupportedWebAssemblyFeatureError");
8
8
 
9
9
  class WasmFinalizeExportsPlugin {
10
10
  apply(compiler) {
@@ -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
- function getAllWasmModules(chunk) {
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
- function generateImportObject(module, mangle) {
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
- function preprocess(ab) {
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
- function compose(...fns) {
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
- function getImportedGlobals(ast) {
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
- function getCountImportedFunc(ast) {
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
- function getNextTypeIndex(ast) {
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
- function getNextFuncIndex(ast, countImportedFunc) {
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
  }
@@ -556,7 +556,7 @@ class JsonpMainTemplatePlugin {
556
556
  }
557
557
  );
558
558
  const runtimeSource = Template.getFunctionContent(
559
- require("./JsonpMainTemplate.runtime.js")
559
+ require("./JsonpMainTemplate.runtime")
560
560
  )
561
561
  .replace(/\/\/\$semicolon/g, ";")
562
562
  .replace(/\$require\$/g, mainTemplate.requireFn)
@@ -1,18 +1,18 @@
1
- /*
2
- MIT License http://www.opensource.org/licenses/mit-license.php
3
- Author Tobias Koppers @sokra
4
- */
5
- "use strict";
6
-
7
- class WebEnvironmentPlugin {
8
- constructor(inputFileSystem, outputFileSystem) {
9
- this.inputFileSystem = inputFileSystem;
10
- this.outputFileSystem = outputFileSystem;
11
- }
12
-
13
- apply(compiler) {
14
- compiler.outputFileSystem = this.outputFileSystem;
15
- }
16
- }
17
-
18
- module.exports = WebEnvironmentPlugin;
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ "use strict";
6
+
7
+ class WebEnvironmentPlugin {
8
+ constructor(inputFileSystem, outputFileSystem) {
9
+ this.inputFileSystem = inputFileSystem;
10
+ this.outputFileSystem = outputFileSystem;
11
+ }
12
+
13
+ apply(compiler) {
14
+ compiler.outputFileSystem = this.outputFileSystem;
15
+ }
16
+ }
17
+
18
+ module.exports = WebEnvironmentPlugin;
package/lib/webpack.js CHANGED
@@ -137,6 +137,10 @@ exportPlugins((exports.optimize = {}), {
137
137
  ModuleConcatenationPlugin: () =>
138
138
  require("./optimize/ModuleConcatenationPlugin"),
139
139
  OccurrenceOrderPlugin: () => require("./optimize/OccurrenceOrderPlugin"),
140
+ OccurrenceModuleOrderPlugin: () =>
141
+ require("./optimize/OccurrenceModuleOrderPlugin"),
142
+ OccurrenceChunkOrderPlugin: () =>
143
+ require("./optimize/OccurrenceChunkOrderPlugin"),
140
144
  RuntimeChunkPlugin: () => require("./optimize/RuntimeChunkPlugin"),
141
145
  SideEffectsFlagPlugin: () => require("./optimize/SideEffectsFlagPlugin"),
142
146
  SplitChunksPlugin: () => require("./optimize/SplitChunksPlugin")
@@ -9,7 +9,7 @@ const WebEnvironmentPlugin = require("./web/WebEnvironmentPlugin");
9
9
  const WebpackOptionsApply = require("./WebpackOptionsApply");
10
10
  const WebpackOptionsDefaulter = require("./WebpackOptionsDefaulter");
11
11
 
12
- function webpack(options, callback) {
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;
@@ -172,7 +172,7 @@ class WebWorkerMainTemplatePlugin {
172
172
  )}];\n` +
173
173
  `${globalObject}[${JSON.stringify(hotUpdateFunction)}] = ` +
174
174
  Template.getFunctionContent(
175
- require("./WebWorkerMainTemplate.runtime.js")
175
+ require("./WebWorkerMainTemplate.runtime")
176
176
  )
177
177
  .replace(/\/\/\$semicolon/g, ";")
178
178
  .replace(/\$require\$/g, mainTemplate.requireFn)