webpack 4.13.0 → 4.16.0

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 (93) hide show
  1. package/bin/webpack.js +7 -2
  2. package/hot/dev-server.js +2 -2
  3. package/hot/only-dev-server.js +2 -2
  4. package/hot/poll.js +5 -2
  5. package/hot/signal.js +2 -2
  6. package/lib/AsyncDependenciesBlock.js +44 -0
  7. package/lib/AutomaticPrefetchPlugin.js +2 -2
  8. package/lib/Chunk.js +56 -6
  9. package/lib/ChunkGroup.js +2 -2
  10. package/lib/ChunkTemplate.js +14 -2
  11. package/lib/CommentCompilationWarning.js +3 -3
  12. package/lib/CompatibilityPlugin.js +1 -1
  13. package/lib/Compilation.js +494 -36
  14. package/lib/Compiler.js +57 -4
  15. package/lib/ContextModule.js +23 -16
  16. package/lib/DelegatedModule.js +9 -1
  17. package/lib/DelegatedModuleFactoryPlugin.js +7 -1
  18. package/lib/DependenciesBlock.js +36 -3
  19. package/lib/DependenciesBlockVariable.js +22 -0
  20. package/lib/Dependency.js +33 -6
  21. package/lib/DllEntryPlugin.js +4 -1
  22. package/lib/DynamicEntryPlugin.js +21 -1
  23. package/lib/EntryOptionPlugin.js +12 -0
  24. package/lib/Entrypoint.js +1 -1
  25. package/lib/EnvironmentPlugin.js +8 -1
  26. package/lib/ExtendedAPIPlugin.js +8 -4
  27. package/lib/ExternalModuleFactoryPlugin.js +1 -1
  28. package/lib/FlagDependencyUsagePlugin.js +18 -13
  29. package/lib/Generator.js +1 -1
  30. package/lib/GraphHelpers.js +2 -1
  31. package/lib/HotModuleReplacement.runtime.js +8 -5
  32. package/lib/HotModuleReplacementPlugin.js +115 -117
  33. package/lib/IgnorePlugin.js +1 -1
  34. package/lib/MainTemplate.js +19 -4
  35. package/lib/Module.js +9 -3
  36. package/lib/ModuleReason.js +8 -0
  37. package/lib/MultiEntryPlugin.js +25 -3
  38. package/lib/NormalModule.js +5 -23
  39. package/lib/RuleSet.js +3 -3
  40. package/lib/RuntimeTemplate.js +4 -0
  41. package/lib/SingleEntryPlugin.js +20 -1
  42. package/lib/Stats.js +12 -5
  43. package/lib/Template.js +4 -1
  44. package/lib/UmdMainTemplatePlugin.js +12 -12
  45. package/lib/UseStrictPlugin.js +1 -1
  46. package/lib/WebpackError.js +4 -0
  47. package/lib/WebpackOptionsApply.js +92 -10
  48. package/lib/WebpackOptionsDefaulter.js +23 -6
  49. package/lib/WebpackOptionsValidationError.js +0 -1
  50. package/lib/compareLocations.js +13 -17
  51. package/lib/debug/ProfilingPlugin.js +5 -7
  52. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +4 -6
  53. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +0 -2
  54. package/lib/dependencies/DependencyReference.js +4 -0
  55. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +18 -8
  56. package/lib/dependencies/LoaderDependency.js +3 -0
  57. package/lib/dependencies/LoaderPlugin.js +21 -2
  58. package/lib/dependencies/ModuleDependency.js +3 -0
  59. package/lib/dependencies/MultiEntryDependency.js +5 -0
  60. package/lib/dependencies/SingleEntryDependency.js +3 -0
  61. package/lib/dependencies/SystemPlugin.js +1 -1
  62. package/lib/formatLocation.js +55 -41
  63. package/lib/node/NodeMainTemplateAsync.runtime.js +1 -1
  64. package/lib/node/NodeMainTemplatePlugin.js +2 -2
  65. package/lib/node/NodeSourcePlugin.js +1 -1
  66. package/lib/optimize/ConcatenatedModule.js +24 -8
  67. package/lib/optimize/ModuleConcatenationPlugin.js +29 -14
  68. package/lib/optimize/NaturalChunkOrderPlugin.js +41 -0
  69. package/lib/optimize/OccurrenceChunkOrderPlugin.js +61 -0
  70. package/lib/optimize/OccurrenceModuleOrderPlugin.js +103 -0
  71. package/lib/optimize/OccurrenceOrderPlugin.js +2 -0
  72. package/lib/optimize/SplitChunksPlugin.js +168 -18
  73. package/lib/util/Semaphore.js +12 -0
  74. package/lib/util/SetHelpers.js +4 -4
  75. package/lib/util/SortableSet.js +1 -1
  76. package/lib/util/cachedMerge.js +1 -1
  77. package/lib/util/createHash.js +15 -0
  78. package/lib/util/deterministicGrouping.js +251 -0
  79. package/lib/util/identifier.js +27 -0
  80. package/lib/wasm/WasmFinalizeExportsPlugin.js +5 -2
  81. package/lib/wasm/WasmMainTemplatePlugin.js +10 -4
  82. package/lib/wasm/WebAssemblyGenerator.js +12 -12
  83. package/lib/wasm/WebAssemblyInInitialChunkError.js +88 -0
  84. package/lib/wasm/WebAssemblyModulesPlugin.js +28 -0
  85. package/lib/web/JsonpMainTemplatePlugin.js +1 -1
  86. package/lib/web/WebEnvironmentPlugin.js +18 -18
  87. package/lib/webpack.js +7 -0
  88. package/lib/webpack.web.js +2 -2
  89. package/lib/webworker/WebWorkerMainTemplatePlugin.js +1 -1
  90. package/package.json +21 -11
  91. package/schemas/WebpackOptions.json +70 -4
  92. package/schemas/plugins/optimize/OccurrenceOrderChunkIdsPlugin.json +10 -0
  93. package/schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json +10 -0
@@ -26,7 +26,6 @@ const ChunkTemplate = require("./ChunkTemplate");
26
26
  const HotUpdateChunkTemplate = require("./HotUpdateChunkTemplate");
27
27
  const ModuleTemplate = require("./ModuleTemplate");
28
28
  const RuntimeTemplate = require("./RuntimeTemplate");
29
- const Dependency = require("./Dependency");
30
29
  const ChunkRenderError = require("./ChunkRenderError");
31
30
  const AsyncDependencyToInitialChunkError = require("./AsyncDependencyToInitialChunkError");
32
31
  const Stats = require("./Stats");
@@ -35,17 +34,91 @@ const createHash = require("./util/createHash");
35
34
  const Queue = require("./util/Queue");
36
35
  const SortableSet = require("./util/SortableSet");
37
36
  const GraphHelpers = require("./GraphHelpers");
37
+ const ModuleDependency = require("./dependencies/ModuleDependency");
38
+ const compareLocations = require("./compareLocations");
38
39
 
39
40
  /** @typedef {import("./Module")} Module */
41
+ /** @typedef {import("./Compiler")} Compiler */
42
+ /** @typedef {import("webpack-sources").Source} Source */
43
+ /** @typedef {import("./WebpackError")} WebpackError */
44
+ /** @typedef {import("./DependenciesBlockVariable")} DependenciesBlockVariable */
45
+ /** @typedef {import("./dependencies/SingleEntryDependency")} SingleEntryDependency */
46
+ /** @typedef {import("./dependencies/MultiEntryDependency")} MultiEntryDependency */
47
+ /** @typedef {import("./dependencies/DllEntryDependency")} DllEntryDependency */
48
+ /** @typedef {import("./dependencies/DependencyReference")} DependencyReference */
40
49
  /** @typedef {import("./DependenciesBlock")} DependenciesBlock */
41
50
  /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
42
-
51
+ /** @typedef {import("./Dependency")} Dependency */
52
+ /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
53
+ /** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
54
+ /** @typedef {import("./util/createHash").Hash} Hash */
55
+
56
+ // TODO use @callback
57
+ /** @typedef {{[assetName: string]: Source}} CompilationAssets */
58
+ /** @typedef {(err: Error|null, result?: Module) => void } ModuleCallback */
59
+ /** @typedef {(err?: Error|null, result?: Module) => void } ModuleChainCallback */
60
+ /** @typedef {(module: Module) => void} OnModuleCallback */
61
+ /** @typedef {(err?: Error|null) => void} Callback */
62
+ /** @typedef {(d: Dependency) => any} DepBlockVarDependenciesCallback */
63
+ /** @typedef {new (...args: any[]) => Dependency} DepConstructor */
64
+ /** @typedef {{apply: () => void}} Plugin */
65
+
66
+ /**
67
+ * @typedef {Object} ModuleFactoryCreateDataContextInfo
68
+ * @property {string} issuer
69
+ * @property {string} compiler
70
+ */
71
+
72
+ /**
73
+ * @typedef {Object} ModuleFactoryCreateData
74
+ * @property {ModuleFactoryCreateDataContextInfo} contextInfo
75
+ * @property {any=} resolveOptions
76
+ * @property {string} context
77
+ * @property {Dependency[]} dependencies
78
+ */
79
+
80
+ /**
81
+ * @typedef {Object} ModuleFactory
82
+ * @property {(data: ModuleFactoryCreateData, callback: ModuleCallback) => any} create
83
+ */
84
+
85
+ /**
86
+ * @typedef {Object} SortedDependency
87
+ * @property {ModuleFactory} factory
88
+ * @property {Dependency[]} dependencies
89
+ */
90
+
91
+ /**
92
+ * @typedef {Object} AvailableModulesChunkGroupMapping
93
+ * @property {ChunkGroup} chunkGroup
94
+ * @property {Set<Module>} availableModules
95
+ */
96
+
97
+ /**
98
+ * @typedef {Object} DependenciesBlockLike
99
+ * @property {Dependency[]} dependencies
100
+ * @property {AsyncDependenciesBlock[]} blocks
101
+ * @property {DependenciesBlockVariable[]} variables
102
+ */
103
+
104
+ /**
105
+ * @param {Chunk} a first chunk to sort by id
106
+ * @param {Chunk} b second chunk to sort by id
107
+ * @returns {-1|0|1} sort value
108
+ */
43
109
  const byId = (a, b) => {
44
- if (a.id < b.id) return -1;
45
- if (a.id > b.id) return 1;
110
+ if (a.id !== null && b.id !== null) {
111
+ if (a.id < b.id) return -1;
112
+ if (a.id > b.id) return 1;
113
+ }
46
114
  return 0;
47
115
  };
48
116
 
117
+ /**
118
+ * @param {Module} a first module to sort by
119
+ * @param {Module} b second module to sort by
120
+ * @returns {-1|0|1} sort value
121
+ */
49
122
  const byIdOrIdentifier = (a, b) => {
50
123
  if (a.id < b.id) return -1;
51
124
  if (a.id > b.id) return 1;
@@ -56,6 +129,11 @@ const byIdOrIdentifier = (a, b) => {
56
129
  return 0;
57
130
  };
58
131
 
132
+ /**
133
+ * @param {Module} a first module to sort by
134
+ * @param {Module} b second module to sort by
135
+ * @returns {-1|0|1} sort value
136
+ */
59
137
  const byIndexOrIdentifier = (a, b) => {
60
138
  if (a.index < b.index) return -1;
61
139
  if (a.index > b.index) return 1;
@@ -66,14 +144,24 @@ const byIndexOrIdentifier = (a, b) => {
66
144
  return 0;
67
145
  };
68
146
 
147
+ /**
148
+ * @param {Compilation} a first compilation to sort by
149
+ * @param {Compilation} b second compilation to sort by
150
+ * @returns {-1|0|1} sort value
151
+ */
69
152
  const byNameOrHash = (a, b) => {
70
153
  if (a.name < b.name) return -1;
71
154
  if (a.name > b.name) return 1;
72
155
  if (a.fullHash < b.fullHash) return -1;
73
- if (a.fullhash > b.fullHash) return 1;
156
+ if (a.fullHash > b.fullHash) return 1;
74
157
  return 0;
75
158
  };
76
159
 
160
+ /**
161
+ * @param {DependenciesBlockVariable[]} variables DepBlock Variables to iterate over
162
+ * @param {DepBlockVarDependenciesCallback} fn callback to apply on iterated elements
163
+ * @returns {void}
164
+ */
77
165
  const iterationBlockVariable = (variables, fn) => {
78
166
  for (
79
167
  let indexVariable = 0;
@@ -87,105 +175,194 @@ const iterationBlockVariable = (variables, fn) => {
87
175
  }
88
176
  };
89
177
 
178
+ /**
179
+ * @template T
180
+ * @param {T[]} arr array of elements to iterate over
181
+ * @param {function(T): void} fn callback applied to each element
182
+ * @returns {void}
183
+ */
90
184
  const iterationOfArrayCallback = (arr, fn) => {
91
185
  for (let index = 0; index < arr.length; index++) {
92
186
  fn(arr[index]);
93
187
  }
94
188
  };
95
189
 
96
- function addAllToSet(set, otherSet) {
190
+ /**
191
+ * @template T
192
+ * @param {Set<T>} set set to add items to
193
+ * @param {Set<T>} otherSet set to add items from
194
+ * @returns {void}
195
+ */
196
+ const addAllToSet = (set, otherSet) => {
97
197
  for (const item of otherSet) {
98
198
  set.add(item);
99
199
  }
100
- }
200
+ };
101
201
 
102
202
  class Compilation extends Tapable {
203
+ /**
204
+ * Creates an instance of Compilation.
205
+ * @param {Compiler} compiler the compiler which created the compilation
206
+ */
103
207
  constructor(compiler) {
104
208
  super();
105
209
  this.hooks = {
210
+ /** @type {SyncHook<Module>} */
106
211
  buildModule: new SyncHook(["module"]),
212
+ /** @type {SyncHook<Module>} */
107
213
  rebuildModule: new SyncHook(["module"]),
214
+ /** @type {SyncHook<Module, Error>} */
108
215
  failedModule: new SyncHook(["module", "error"]),
216
+ /** @type {SyncHook<Module>} */
109
217
  succeedModule: new SyncHook(["module"]),
110
218
 
219
+ /** @type {SyncWaterfallHook<DependencyReference, Dependency, Module>} */
220
+ dependencyReference: new SyncWaterfallHook([
221
+ "dependencyReference",
222
+ "dependency",
223
+ "module"
224
+ ]),
225
+
226
+ /** @type {SyncHook<Module[]>} */
111
227
  finishModules: new SyncHook(["modules"]),
228
+ /** @type {SyncHook<Module>} */
112
229
  finishRebuildingModule: new SyncHook(["module"]),
113
-
230
+ /** @type {SyncHook} */
114
231
  unseal: new SyncHook([]),
232
+ /** @type {SyncHook} */
115
233
  seal: new SyncHook([]),
116
234
 
235
+ /** @type {SyncHook} */
236
+ beforeChunks: new SyncHook([]),
237
+ /** @type {SyncHook<Chunk[]>} */
238
+ afterChunks: new SyncHook(["chunks"]),
239
+
240
+ /** @type {SyncBailHook<Module[]>} */
117
241
  optimizeDependenciesBasic: new SyncBailHook(["modules"]),
242
+ /** @type {SyncBailHook<Module[]>} */
118
243
  optimizeDependencies: new SyncBailHook(["modules"]),
244
+ /** @type {SyncBailHook<Module[]>} */
119
245
  optimizeDependenciesAdvanced: new SyncBailHook(["modules"]),
246
+ /** @type {SyncBailHook<Module[]>} */
120
247
  afterOptimizeDependencies: new SyncHook(["modules"]),
121
248
 
249
+ /** @type {SyncHook} */
122
250
  optimize: new SyncHook([]),
123
-
251
+ /** @type {SyncBailHook<Module[]>} */
124
252
  optimizeModulesBasic: new SyncBailHook(["modules"]),
253
+ /** @type {SyncBailHook<Module[]>} */
125
254
  optimizeModules: new SyncBailHook(["modules"]),
255
+ /** @type {SyncBailHook<Module[]>} */
126
256
  optimizeModulesAdvanced: new SyncBailHook(["modules"]),
257
+ /** @type {SyncHook<Module[]>} */
127
258
  afterOptimizeModules: new SyncHook(["modules"]),
128
259
 
260
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
129
261
  optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]),
262
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
130
263
  optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
264
+ /** @type {SyncBailHook<Chunk[], ChunkGroup[]>} */
131
265
  optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]),
266
+ /** @type {SyncHook<Chunk[], ChunkGroup[]>} */
132
267
  afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),
133
268
 
269
+ /** @type {AsyncSeriesHook<Chunk[], Module[]>} */
134
270
  optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
271
+ /** @type {SyncHook<Chunk[], Module[]>} */
135
272
  afterOptimizeTree: new SyncHook(["chunks", "modules"]),
136
273
 
274
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
137
275
  optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]),
276
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
138
277
  optimizeChunkModules: new SyncBailHook(["chunks", "modules"]),
278
+ /** @type {SyncBailHook<Chunk[], Module[]>} */
139
279
  optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]),
280
+ /** @type {SyncHook<Chunk[], Module[]>} */
140
281
  afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
282
+ /** @type {SyncBailHook} */
141
283
  shouldRecord: new SyncBailHook([]),
142
284
 
285
+ /** @type {SyncHook<Module[], any>} */
143
286
  reviveModules: new SyncHook(["modules", "records"]),
287
+ /** @type {SyncHook<Module[]>} */
144
288
  optimizeModuleOrder: new SyncHook(["modules"]),
289
+ /** @type {SyncHook<Module[]>} */
145
290
  advancedOptimizeModuleOrder: new SyncHook(["modules"]),
291
+ /** @type {SyncHook<Module[]>} */
146
292
  beforeModuleIds: new SyncHook(["modules"]),
293
+ /** @type {SyncHook<Module[]>} */
147
294
  moduleIds: new SyncHook(["modules"]),
295
+ /** @type {SyncHook<Module[]>} */
148
296
  optimizeModuleIds: new SyncHook(["modules"]),
297
+ /** @type {SyncHook<Module[]>} */
149
298
  afterOptimizeModuleIds: new SyncHook(["modules"]),
150
299
 
300
+ /** @type {SyncHook<Chunk[], any>} */
151
301
  reviveChunks: new SyncHook(["chunks", "records"]),
302
+ /** @type {SyncHook<Chunk[]>} */
152
303
  optimizeChunkOrder: new SyncHook(["chunks"]),
304
+ /** @type {SyncHook<Chunk[]>} */
153
305
  beforeChunkIds: new SyncHook(["chunks"]),
306
+ /** @type {SyncHook<Chunk[]>} */
154
307
  optimizeChunkIds: new SyncHook(["chunks"]),
308
+ /** @type {SyncHook<Chunk[]>} */
155
309
  afterOptimizeChunkIds: new SyncHook(["chunks"]),
156
310
 
311
+ /** @type {SyncHook<Module[], any>} */
157
312
  recordModules: new SyncHook(["modules", "records"]),
313
+ /** @type {SyncHook<Chunk[], any>} */
158
314
  recordChunks: new SyncHook(["chunks", "records"]),
159
315
 
316
+ /** @type {SyncHook} */
160
317
  beforeHash: new SyncHook([]),
318
+ /** @type {SyncHook<Chunk>} */
161
319
  contentHash: new SyncHook(["chunk"]),
320
+ /** @type {SyncHook} */
162
321
  afterHash: new SyncHook([]),
163
-
322
+ /** @type {SyncHook<any>} */
164
323
  recordHash: new SyncHook(["records"]),
165
-
324
+ /** @type {SyncHook<Compilation, any>} */
166
325
  record: new SyncHook(["compilation", "records"]),
167
326
 
327
+ /** @type {SyncHook} */
168
328
  beforeModuleAssets: new SyncHook([]),
329
+ /** @type {SyncBailHook} */
169
330
  shouldGenerateChunkAssets: new SyncBailHook([]),
331
+ /** @type {SyncHook} */
170
332
  beforeChunkAssets: new SyncHook([]),
333
+ /** @type {SyncHook<Chunk[]>} */
171
334
  additionalChunkAssets: new SyncHook(["chunks"]),
172
335
 
336
+ /** @type {AsyncSeriesHook} */
173
337
  additionalAssets: new AsyncSeriesHook([]),
338
+ /** @type {AsyncSeriesHook<Chunk[]>} */
174
339
  optimizeChunkAssets: new AsyncSeriesHook(["chunks"]),
340
+ /** @type {SyncHook<Chunk[]>} */
175
341
  afterOptimizeChunkAssets: new SyncHook(["chunks"]),
342
+ /** @type {AsyncSeriesHook<CompilationAssets>} */
176
343
  optimizeAssets: new AsyncSeriesHook(["assets"]),
344
+ /** @type {SyncHook<CompilationAssets>} */
177
345
  afterOptimizeAssets: new SyncHook(["assets"]),
178
346
 
347
+ /** @type {SyncBailHook} */
179
348
  needAdditionalSeal: new SyncBailHook([]),
349
+ /** @type {AsyncSeriesHook} */
180
350
  afterSeal: new AsyncSeriesHook([]),
181
351
 
352
+ /** @type {SyncHook<Chunk, Hash>} */
182
353
  chunkHash: new SyncHook(["chunk", "chunkHash"]),
354
+ /** @type {SyncHook<Module, string>} */
183
355
  moduleAsset: new SyncHook(["module", "filename"]),
356
+ /** @type {SyncHook<Chunk, string>} */
184
357
  chunkAsset: new SyncHook(["chunk", "filename"]),
185
358
 
359
+ /** @type {SyncWaterfallHook<string, TODO>} */
186
360
  assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate
187
361
 
362
+ /** @type {SyncBailHook} */
188
363
  needAdditionalPass: new SyncBailHook([]),
364
+
365
+ /** @type {SyncHook<Compiler, string, number>} */
189
366
  childCompiler: new SyncHook([
190
367
  "childCompiler",
191
368
  "compilerName",
@@ -194,11 +371,16 @@ class Compilation extends Tapable {
194
371
 
195
372
  // TODO the following hooks are weirdly located here
196
373
  // TODO move them for webpack 5
374
+ /** @type {SyncHook<object, Module>} */
197
375
  normalModuleLoader: new SyncHook(["loaderContext", "module"]),
198
376
 
377
+ /** @type {SyncBailHook<Chunk[]>} */
199
378
  optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]),
379
+ /** @type {SyncBailHook<Chunk[]>} */
200
380
  optimizeExtractedChunks: new SyncBailHook(["chunks"]),
381
+ /** @type {SyncBailHook<Chunk[]>} */
201
382
  optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]),
383
+ /** @type {SyncHook<Chunk[]>} */
202
384
  afterOptimizeExtractedChunks: new SyncHook(["chunks"])
203
385
  };
204
386
  this._pluginCompat.tap("Compilation", options => {
@@ -212,7 +394,9 @@ class Compilation extends Tapable {
212
394
  break;
213
395
  }
214
396
  });
397
+ /** @type {string=} */
215
398
  this.name = undefined;
399
+ /** @type {Compiler} */
216
400
  this.compiler = compiler;
217
401
  this.resolverFactory = compiler.resolverFactory;
218
402
  this.inputFileSystem = compiler.inputFileSystem;
@@ -220,6 +404,7 @@ class Compilation extends Tapable {
220
404
 
221
405
  const options = (this.options = compiler.options);
222
406
  this.outputOptions = options && options.output;
407
+ /** @type {boolean=} */
223
408
  this.bail = options && options.bail;
224
409
  this.profile = options && options.profile;
225
410
  this.performance = options && options.performance;
@@ -241,32 +426,53 @@ class Compilation extends Tapable {
241
426
  this.semaphore = new Semaphore(options.parallelism || 100);
242
427
 
243
428
  this.entries = [];
429
+ /** @private @type {{name: string, request: string, module: Module}[]} */
244
430
  this._preparedEntrypoints = [];
245
431
  this.entrypoints = new Map();
432
+ /** @type {Chunk[]} */
246
433
  this.chunks = [];
434
+ /** @type {ChunkGroup[]} */
247
435
  this.chunkGroups = [];
436
+ /** @type {Map<string, ChunkGroup>} */
248
437
  this.namedChunkGroups = new Map();
438
+ /** @type {Map<string, Chunk>} */
249
439
  this.namedChunks = new Map();
440
+ /** @type {Module[]} */
250
441
  this.modules = [];
442
+ /** @private @type {Map<string, Module>} */
251
443
  this._modules = new Map();
252
444
  this.cache = null;
253
445
  this.records = null;
446
+ /** @type {string[]} */
254
447
  this.additionalChunkAssets = [];
448
+ /** @type {CompilationAssets} */
255
449
  this.assets = {};
450
+ /** @type {WebpackError[]} */
256
451
  this.errors = [];
452
+ /** @type {WebpackError[]} */
257
453
  this.warnings = [];
454
+ /** @type {Compilation[]} */
258
455
  this.children = [];
456
+ /** @type {Map<DepConstructor, ModuleFactory>} */
259
457
  this.dependencyFactories = new Map();
458
+ /** @type {Map<DepConstructor|string, DependencyTemplate|string>} */
260
459
  this.dependencyTemplates = new Map();
460
+ // TODO refactor this in webpack 5 to a custom DependencyTemplates class with a hash property
261
461
  this.dependencyTemplates.set("hash", "");
262
462
  this.childrenCounters = {};
463
+ /** @type {Set<number|string>} */
263
464
  this.usedChunkIds = null;
465
+ /** @type {Set<number>} */
264
466
  this.usedModuleIds = null;
467
+ /** @type {Map<string, number>=} */
265
468
  this.fileTimestamps = undefined;
469
+ /** @type {Map<string, number>=} */
266
470
  this.contextTimestamps = undefined;
471
+ /** @type {Set<string>=} */
267
472
  this.compilationDependencies = undefined;
268
-
473
+ /** @private @type {Map<Module, Callback[]>} */
269
474
  this._buildingModules = new Map();
475
+ /** @private @type {Map<Module, Callback[]>} */
270
476
  this._rebuildingModules = new Map();
271
477
  }
272
478
 
@@ -274,6 +480,20 @@ class Compilation extends Tapable {
274
480
  return new Stats(this);
275
481
  }
276
482
 
483
+ /**
484
+ * @typedef {Object} AddModuleResult
485
+ * @property {Module} module the added or existing module
486
+ * @property {boolean} issuer was this the first request for this module
487
+ * @property {boolean} build should the module be build
488
+ * @property {boolean} dependencies should dependencies be walked
489
+ */
490
+
491
+ /**
492
+ * @param {Module} module module to be added that was created
493
+ * @param {any=} cacheGroup cacheGroup it is apart of
494
+ * @returns {AddModuleResult} returns meta about whether or not the module had built
495
+ * had an issuer, or any dependnecies
496
+ */
277
497
  addModule(module, cacheGroup) {
278
498
  const identifier = module.identifier();
279
499
  const alreadyAddedModule = this._modules.get(identifier);
@@ -334,15 +554,30 @@ class Compilation extends Tapable {
334
554
  };
335
555
  }
336
556
 
557
+ /**
558
+ * Fetches a module from a compilation by its identifier
559
+ * @param {Module} module the module provided
560
+ * @returns {Module} the module requested
561
+ */
337
562
  getModule(module) {
338
563
  const identifier = module.identifier();
339
564
  return this._modules.get(identifier);
340
565
  }
341
566
 
567
+ /**
568
+ * Attempts to search for a module by its identifier
569
+ * @param {string} identifier identifier (usually path) for module
570
+ * @returns {Module|undefined} attempt to search for module and return it, else undefined
571
+ */
342
572
  findModule(identifier) {
343
573
  return this._modules.get(identifier);
344
574
  }
345
575
 
576
+ /**
577
+ * @param {Module} module module with its callback list
578
+ * @param {Callback} callback the callback function
579
+ * @returns {void}
580
+ */
346
581
  waitForBuildingFinished(module, callback) {
347
582
  let callbackList = this._buildingModules.get(module);
348
583
  if (callbackList) {
@@ -352,6 +587,16 @@ class Compilation extends Tapable {
352
587
  }
353
588
  }
354
589
 
590
+ /**
591
+ * Builds the module object
592
+ *
593
+ * @param {Module} module module to be built
594
+ * @param {boolean} optional optional flag
595
+ * @param {Module=} origin origin module this module build was requested from
596
+ * @param {Dependency[]=} dependencies optional dependencies from the module to be built
597
+ * @param {TODO} thisCallback the callback
598
+ * @returns {TODO} returns the callback function with results
599
+ */
355
600
  buildModule(module, optional, origin, dependencies, thisCallback) {
356
601
  let callbackList = this._buildingModules.get(module);
357
602
  if (callbackList) {
@@ -397,7 +642,7 @@ class Compilation extends Tapable {
397
642
  war.dependencies = dependencies;
398
643
  this.warnings.push(war);
399
644
  }
400
- module.dependencies.sort(Dependency.compare);
645
+ module.dependencies.sort((a, b) => compareLocations(a.loc, b.loc));
401
646
  if (error) {
402
647
  this.hooks.failedModule.call(module, error);
403
648
  return callback(error);
@@ -408,6 +653,11 @@ class Compilation extends Tapable {
408
653
  );
409
654
  }
410
655
 
656
+ /**
657
+ * @param {Module} module to be processed for deps
658
+ * @param {ModuleCallback} callback callback to be triggered
659
+ * @returns {void}
660
+ */
411
661
  processModuleDependencies(module, callback) {
412
662
  const dependencies = new Map();
413
663
 
@@ -471,6 +721,15 @@ class Compilation extends Tapable {
471
721
  );
472
722
  }
473
723
 
724
+ /**
725
+ * @param {Module} module module to add deps to
726
+ * @param {SortedDependency[]} dependencies set of sorted dependencies to iterate through
727
+ * @param {(boolean|null)=} bail whether to bail or not
728
+ * @param {TODO} cacheGroup optional cacheGroup
729
+ * @param {boolean} recursive whether it is recursive traversal
730
+ * @param {function} callback callback for when dependencies are finished being added
731
+ * @returns {void}
732
+ */
474
733
  addModuleDependencies(
475
734
  module,
476
735
  dependencies,
@@ -638,6 +897,14 @@ class Compilation extends Tapable {
638
897
  );
639
898
  }
640
899
 
900
+ /**
901
+ *
902
+ * @param {string} context context string path
903
+ * @param {Dependency} dependency dependency used to create Module chain
904
+ * @param {OnModuleCallback} onModule function invoked on modules creation
905
+ * @param {ModuleChainCallback} callback callback for when module chain is complete
906
+ * @returns {void} will throw if dependency instance is not a valid Dependency
907
+ */
641
908
  _addModuleChain(context, dependency, onModule, callback) {
642
909
  const start = this.profile && Date.now();
643
910
  const currentProfile = this.profile && {};
@@ -659,8 +926,8 @@ class Compilation extends Tapable {
659
926
  ) {
660
927
  throw new Error("Parameter 'dependency' must be a Dependency");
661
928
  }
662
-
663
- const moduleFactory = this.dependencyFactories.get(dependency.constructor);
929
+ const Dep = /** @type {DepConstructor} */ (dependency.constructor);
930
+ const moduleFactory = this.dependencyFactories.get(Dep);
664
931
  if (!moduleFactory) {
665
932
  throw new Error(
666
933
  `No dependency factory available for this dependency type: ${
@@ -746,12 +1013,25 @@ class Compilation extends Tapable {
746
1013
  });
747
1014
  }
748
1015
 
1016
+ /**
1017
+ *
1018
+ * @param {string} context context path for entry
1019
+ * @param {Dependency} entry entry dependency being created
1020
+ * @param {string} name name of entry
1021
+ * @param {ModuleCallback} callback callback function
1022
+ * @returns {void} returns
1023
+ */
749
1024
  addEntry(context, entry, name, callback) {
750
1025
  const slot = {
751
1026
  name: name,
752
- request: entry.request,
1027
+ request: null,
753
1028
  module: null
754
1029
  };
1030
+
1031
+ if (entry instanceof ModuleDependency) {
1032
+ slot.request = entry.request;
1033
+ }
1034
+
755
1035
  this._preparedEntrypoints.push(slot);
756
1036
  this._addModuleChain(
757
1037
  context,
@@ -775,6 +1055,12 @@ class Compilation extends Tapable {
775
1055
  );
776
1056
  }
777
1057
 
1058
+ /**
1059
+ * @param {string} context context path string
1060
+ * @param {Dependency} dependency dep used to create module
1061
+ * @param {ModuleCallback} callback module callback sending module up a level
1062
+ * @returns {void}
1063
+ */
778
1064
  prefetch(context, dependency, callback) {
779
1065
  this._addModuleChain(
780
1066
  context,
@@ -786,6 +1072,11 @@ class Compilation extends Tapable {
786
1072
  );
787
1073
  }
788
1074
 
1075
+ /**
1076
+ * @param {Module} module module to be rebuilt
1077
+ * @param {Callback} thisCallback callback when module finishes rebuilding
1078
+ * @returns {void}
1079
+ */
789
1080
  rebuildModule(module, thisCallback) {
790
1081
  let callbackList = this._rebuildingModules.get(module);
791
1082
  if (callbackList) {
@@ -848,6 +1139,10 @@ class Compilation extends Tapable {
848
1139
  }
849
1140
  }
850
1141
 
1142
+ /**
1143
+ * @param {Callback} callback signals when the seal method is finishes
1144
+ * @returns {void}
1145
+ */
851
1146
  seal(callback) {
852
1147
  this.hooks.seal.call();
853
1148
 
@@ -860,6 +1155,7 @@ class Compilation extends Tapable {
860
1155
  }
861
1156
  this.hooks.afterOptimizeDependencies.call(this.modules);
862
1157
 
1158
+ this.hooks.beforeChunks.call();
863
1159
  for (const preparedEntrypoint of this._preparedEntrypoints) {
864
1160
  const module = preparedEntrypoint.module;
865
1161
  const name = preparedEntrypoint.name;
@@ -881,6 +1177,8 @@ class Compilation extends Tapable {
881
1177
  }
882
1178
  this.processDependenciesBlocksForChunkGroups(this.chunkGroups.slice());
883
1179
  this.sortModules(this.modules);
1180
+ this.hooks.afterChunks.call(this.chunks);
1181
+
884
1182
  this.hooks.optimize.call();
885
1183
 
886
1184
  while (
@@ -989,10 +1287,22 @@ class Compilation extends Tapable {
989
1287
  });
990
1288
  }
991
1289
 
1290
+ /**
1291
+ * @param {Module[]} modules the modules array on compilation to perform the sort for
1292
+ * @returns {void}
1293
+ */
992
1294
  sortModules(modules) {
1295
+ // TODO webpack 5: this should only be enabled when `moduleIds: "natural"`
1296
+ // TODO move it into a plugin (NaturalModuleIdsPlugin) and use this in WebpackOptionsApply
1297
+ // TODO remove this method
993
1298
  modules.sort(byIndexOrIdentifier);
994
1299
  }
995
1300
 
1301
+ /**
1302
+ * @param {Module} module moulde to report from
1303
+ * @param {DependenciesBlock[]} blocks blocks to report from
1304
+ * @returns {void}
1305
+ */
996
1306
  reportDependencyErrorsAndWarnings(module, blocks) {
997
1307
  for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
998
1308
  const block = blocks[indexBlock];
@@ -1028,7 +1338,7 @@ class Compilation extends Tapable {
1028
1338
  /**
1029
1339
  * @param {TODO} groupOptions options for the chunk group
1030
1340
  * @param {Module} module the module the references the chunk group
1031
- * @param {TODO} loc the location from with the chunk group is reference (inside of module)
1341
+ * @param {DependencyLocation} loc the location from with the chunk group is referenced (inside of module)
1032
1342
  * @param {string} request the request from which the the chunk group is referenced
1033
1343
  * @returns {ChunkGroup} the new or existing chunk group
1034
1344
  */
@@ -1060,6 +1370,13 @@ class Compilation extends Tapable {
1060
1370
  return chunkGroup;
1061
1371
  }
1062
1372
 
1373
+ /**
1374
+ * This method first looks to see if a name is provided for a new chunk,
1375
+ * and first looks to see if any named chunks already exist and reuse that chunk instead.
1376
+ *
1377
+ * @param {string=} name optional chunk name to be provided
1378
+ * @returns {Chunk} create a chunk (invoked during seal event)
1379
+ */
1063
1380
  addChunk(name) {
1064
1381
  if (name) {
1065
1382
  const chunk = this.namedChunks.get(name);
@@ -1075,12 +1392,20 @@ class Compilation extends Tapable {
1075
1392
  return chunk;
1076
1393
  }
1077
1394
 
1395
+ /**
1396
+ * @param {Module} module module to assign depth
1397
+ * @returns {void}
1398
+ */
1078
1399
  assignDepth(module) {
1079
1400
  const queue = new Set([module]);
1080
1401
  let depth;
1081
1402
 
1082
1403
  module.depth = 0;
1083
1404
 
1405
+ /**
1406
+ * @param {Module} module module for processeing
1407
+ * @returns {void}
1408
+ */
1084
1409
  const enqueueJob = module => {
1085
1410
  const d = module.depth;
1086
1411
  if (typeof d === "number" && d <= depth) return;
@@ -1088,12 +1413,20 @@ class Compilation extends Tapable {
1088
1413
  module.depth = depth;
1089
1414
  };
1090
1415
 
1091
- const assignDepthToDependency = (dependency, depth) => {
1416
+ /**
1417
+ * @param {Dependency} dependency dependency to assign depth to
1418
+ * @returns {void}
1419
+ */
1420
+ const assignDepthToDependency = dependency => {
1092
1421
  if (dependency.module) {
1093
1422
  enqueueJob(dependency.module);
1094
1423
  }
1095
1424
  };
1096
1425
 
1426
+ /**
1427
+ * @param {DependenciesBlock} block block to assign depth to
1428
+ * @returns {void}
1429
+ */
1097
1430
  const assignDepthToDependencyBlock = block => {
1098
1431
  if (block.variables) {
1099
1432
  iterationBlockVariable(block.variables, assignDepthToDependency);
@@ -1117,6 +1450,19 @@ class Compilation extends Tapable {
1117
1450
  }
1118
1451
  }
1119
1452
 
1453
+ /**
1454
+ * @param {Module} module the module containing the dependency
1455
+ * @param {Dependency} dependency the dependency
1456
+ * @returns {DependencyReference} a reference for the dependency
1457
+ */
1458
+ getDependencyReference(module, dependency) {
1459
+ // TODO remove dep.getReference existence check in webpack 5
1460
+ if (typeof dependency.getReference !== "function") return null;
1461
+ const ref = dependency.getReference();
1462
+ if (!ref) return null;
1463
+ return this.hooks.dependencyReference.call(ref, dependency, module);
1464
+ }
1465
+
1120
1466
  /**
1121
1467
  * This method creates the Chunk graph from the Module graph
1122
1468
  * @private
@@ -1132,7 +1478,7 @@ class Compilation extends Tapable {
1132
1478
  // eachother and Blocks with Chunks. It stops traversing when all modules
1133
1479
  // for a chunk are already available. So it doesn't connect unneeded chunks.
1134
1480
 
1135
- /** @type {Map<Chunk, {block: DependenciesBlock, chunkGroup: ChunkGroup}[]>} */
1481
+ /** @type {Map<ChunkGroup, {block: AsyncDependenciesBlock, chunkGroup: ChunkGroup}[]>} */
1136
1482
  const chunkDependencies = new Map();
1137
1483
  const allCreatedChunkGroups = new Set();
1138
1484
 
@@ -1140,9 +1486,13 @@ class Compilation extends Tapable {
1140
1486
  /** @type {Map<DependenciesBlock, { modules: Module[], blocks: AsyncDependenciesBlock[]}>} */
1141
1487
  const blockInfoMap = new Map();
1142
1488
 
1489
+ /**
1490
+ * @param {Dependency} d dependency to iterate over
1491
+ * @returns {void}
1492
+ */
1143
1493
  const iteratorDependency = d => {
1144
1494
  // We skip Dependencies without Reference
1145
- const ref = d.getReference();
1495
+ const ref = this.getDependencyReference(currentModule, d);
1146
1496
  if (!ref) {
1147
1497
  return;
1148
1498
  }
@@ -1159,22 +1509,29 @@ class Compilation extends Tapable {
1159
1509
  blockInfoModules.add(refModule);
1160
1510
  };
1161
1511
 
1512
+ /**
1513
+ * @param {AsyncDependenciesBlock} b blocks to prepare
1514
+ * @returns {void}
1515
+ */
1162
1516
  const iteratorBlockPrepare = b => {
1163
1517
  blockInfoBlocks.push(b);
1164
1518
  blockQueue.push(b);
1165
1519
  };
1166
1520
 
1521
+ /** @type {Module} */
1522
+ let currentModule;
1167
1523
  /** @type {DependenciesBlock} */
1168
1524
  let block;
1169
- /** @type {TODO} */
1525
+ /** @type {DependenciesBlock[]} */
1170
1526
  let blockQueue;
1171
- /** @type {Set<TODO>} */
1527
+ /** @type {Set<Module>} */
1172
1528
  let blockInfoModules;
1173
- /** @type {TODO[]} */
1529
+ /** @type {AsyncDependenciesBlock[]} */
1174
1530
  let blockInfoBlocks;
1175
1531
 
1176
1532
  for (const module of this.modules) {
1177
1533
  blockQueue = [module];
1534
+ currentModule = module;
1178
1535
  while (blockQueue.length > 0) {
1179
1536
  block = blockQueue.pop();
1180
1537
  blockInfoModules = new Set();
@@ -1246,9 +1603,18 @@ class Compilation extends Tapable {
1246
1603
  /** @type {QueueItem[]} */
1247
1604
  let queueDelayed = [];
1248
1605
 
1249
- let module, chunk, chunkGroup;
1606
+ /** @type {Module} */
1607
+ let module;
1608
+ /** @type {Chunk} */
1609
+ let chunk;
1610
+ /** @type {ChunkGroup} */
1611
+ let chunkGroup;
1250
1612
 
1251
1613
  // For each async Block in graph
1614
+ /**
1615
+ * @param {AsyncDependenciesBlock} b iterating over each Async DepBlock
1616
+ * @returns {void}
1617
+ */
1252
1618
  const iteratorBlock = b => {
1253
1619
  // 1. We create a chunk for this Block
1254
1620
  // but only once (blockChunkGroups map)
@@ -1390,9 +1756,10 @@ class Compilation extends Tapable {
1390
1756
  }
1391
1757
 
1392
1758
  // PART TWO
1393
-
1759
+ /** @type {Set<Module>} */
1394
1760
  let availableModules;
1395
1761
  let newAvailableModules;
1762
+ /** @type {Queue<AvailableModulesChunkGroupMapping>} */
1396
1763
  const queue2 = new Queue(
1397
1764
  inputChunkGroups.map(chunkGroup => ({
1398
1765
  chunkGroup,
@@ -1400,7 +1767,13 @@ class Compilation extends Tapable {
1400
1767
  }))
1401
1768
  );
1402
1769
 
1403
- // Helper function to check if all modules of a chunk are available
1770
+ /**
1771
+ * Helper function to check if all modules of a chunk are available
1772
+ *
1773
+ * @param {ChunkGroup} chunkGroup the chunkGroup to scan
1774
+ * @param {Set<Module>} availableModules the comparitor set
1775
+ * @returns {boolean} return true if all modules of a chunk are available
1776
+ */
1404
1777
  const areModulesAvailable = (chunkGroup, availableModules) => {
1405
1778
  for (const chunk of chunkGroup.chunks) {
1406
1779
  for (const module of chunk.modulesIterable) {
@@ -1411,14 +1784,18 @@ class Compilation extends Tapable {
1411
1784
  };
1412
1785
 
1413
1786
  // For each edge in the basic chunk graph
1787
+ /**
1788
+ * @param {TODO} dep the dependency used for filtering
1789
+ * @returns {boolean} used to filter "edges" (aka Dependencies) that were pointing
1790
+ * to modules that are already available. Also filters circular dependencies in the chunks graph
1791
+ */
1414
1792
  const filterFn = dep => {
1415
- // Filter egdes that are not needed because all modules are already available
1416
- // This also filters circular dependencies in the chunks graph
1417
1793
  const depChunkGroup = dep.chunkGroup;
1418
1794
  if (areModulesAvailable(depChunkGroup, newAvailableModules)) return false; // break all modules are already available
1419
1795
  return true;
1420
1796
  };
1421
1797
 
1798
+ /** @type {Map<ChunkGroup, Set<Module>>} */
1422
1799
  const minAvailableModulesMap = new Map();
1423
1800
 
1424
1801
  // Iterative traversing of the basic chunk graph
@@ -1503,6 +1880,12 @@ class Compilation extends Tapable {
1503
1880
  }
1504
1881
  }
1505
1882
 
1883
+ /**
1884
+ *
1885
+ * @param {Module} module module relationship for removal
1886
+ * @param {DependenciesBlockLike} block //TODO: good description
1887
+ * @returns {void}
1888
+ */
1506
1889
  removeReasonsOfDependencyBlock(module, block) {
1507
1890
  const iteratorDependency = d => {
1508
1891
  if (!d.module) {
@@ -1530,6 +1913,11 @@ class Compilation extends Tapable {
1530
1913
  }
1531
1914
  }
1532
1915
 
1916
+ /**
1917
+ * @param {Module} module module to patch tie
1918
+ * @param {Chunk} chunk chunk to patch tie
1919
+ * @returns {void}
1920
+ */
1533
1921
  patchChunksAfterReasonRemoval(module, chunk) {
1534
1922
  if (!module.hasReasons()) {
1535
1923
  this.removeReasonsOfDependencyBlock(module, module);
@@ -1541,6 +1929,12 @@ class Compilation extends Tapable {
1541
1929
  }
1542
1930
  }
1543
1931
 
1932
+ /**
1933
+ *
1934
+ * @param {DependenciesBlock} block block tie for Chunk
1935
+ * @param {Chunk} chunk chunk to remove from dep
1936
+ * @returns {void}
1937
+ */
1544
1938
  removeChunkFromDependencies(block, chunk) {
1545
1939
  const iteratorDependency = d => {
1546
1940
  if (!d.module) {
@@ -1551,12 +1945,16 @@ class Compilation extends Tapable {
1551
1945
 
1552
1946
  const blocks = block.blocks;
1553
1947
  for (let indexBlock = 0; indexBlock < blocks.length; indexBlock++) {
1554
- const chunks = blocks[indexBlock].chunks;
1948
+ const asyncBlock = blocks[indexBlock];
1949
+ // Grab all chunks from the first Block's AsyncDepBlock
1950
+ const chunks = asyncBlock.chunkGroup.chunks;
1951
+ // For each chunk in chunkGroup
1555
1952
  for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
1556
- const blockChunk = chunks[indexChunk];
1557
- chunk.removeChunk(blockChunk);
1558
- blockChunk.removeParent(chunk);
1559
- this.removeChunkFromDependencies(chunks, blockChunk);
1953
+ const iteratedChunk = chunks[indexChunk];
1954
+ asyncBlock.chunkGroup.removeChunk(iteratedChunk);
1955
+ asyncBlock.chunkGroup.removeParent(iteratedChunk);
1956
+ // Recurse
1957
+ this.removeChunkFromDependencies(block, iteratedChunk);
1560
1958
  }
1561
1959
  }
1562
1960
 
@@ -1620,6 +2018,7 @@ class Compilation extends Tapable {
1620
2018
  }
1621
2019
 
1622
2020
  applyChunkIds() {
2021
+ /** @type {Set<number>} */
1623
2022
  const usedIds = new Set();
1624
2023
 
1625
2024
  // Get used ids from usedChunkIds property (i. e. from records)
@@ -1654,6 +2053,7 @@ class Compilation extends Tapable {
1654
2053
  nextFreeChunkId++;
1655
2054
 
1656
2055
  // Determine free chunk ids from 0 to maximum
2056
+ /** @type {number[]} */
1657
2057
  const unusedIds = [];
1658
2058
  if (nextFreeChunkId > 0) {
1659
2059
  let index = nextFreeChunkId;
@@ -1690,7 +2090,7 @@ class Compilation extends Tapable {
1690
2090
 
1691
2091
  const chunks = this.chunks;
1692
2092
  for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
1693
- chunks[indexChunk].sortItems(false);
2093
+ chunks[indexChunk].sortItems();
1694
2094
  }
1695
2095
  }
1696
2096
 
@@ -1711,9 +2111,19 @@ class Compilation extends Tapable {
1711
2111
 
1712
2112
  const chunks = this.chunks;
1713
2113
  for (let indexChunk = 0; indexChunk < chunks.length; indexChunk++) {
1714
- chunks[indexChunk].sortItems(true);
2114
+ chunks[indexChunk].sortItems();
1715
2115
  }
1716
2116
 
2117
+ /**
2118
+ * Used to sort errors and warnings in compilation. this.warnings, and
2119
+ * this.errors contribute to the compilation hash and therefore should be
2120
+ * updated whenever other references (having a chunk id) are sorted. This preserves the hash
2121
+ * integrity
2122
+ *
2123
+ * @param {WebpackError} a first WebpackError instance (including subclasses)
2124
+ * @param {WebpackError} b second WebpackError instance (including subclasses)
2125
+ * @returns {-1|0|1} sort order index
2126
+ */
1717
2127
  const byMessage = (a, b) => {
1718
2128
  const ma = `${a.message}`;
1719
2129
  const mb = `${b.message}`;
@@ -1841,6 +2251,10 @@ class Compilation extends Tapable {
1841
2251
  this.hash = this.fullHash.substr(0, hashDigestLength);
1842
2252
  }
1843
2253
 
2254
+ /**
2255
+ * @param {string} update extra information
2256
+ * @returns {void}
2257
+ */
1844
2258
  modifyHash(update) {
1845
2259
  const outputOptions = this.outputOptions;
1846
2260
  const hashFunction = outputOptions.hashFunction;
@@ -1869,6 +2283,8 @@ class Compilation extends Tapable {
1869
2283
  createChunkAssets() {
1870
2284
  const outputOptions = this.outputOptions;
1871
2285
  const cachedSourceMap = new Map();
2286
+ /** @type {Map<string, {hash: string, source: Source, chunk: Chunk}>} */
2287
+ const alreadyWrittenFiles = new Map();
1872
2288
  for (let i = 0; i < this.chunks.length; i++) {
1873
2289
  const chunk = this.chunks[i];
1874
2290
  chunk.files = [];
@@ -1891,6 +2307,28 @@ class Compilation extends Tapable {
1891
2307
  const cacheName = fileManifest.identifier;
1892
2308
  const usedHash = fileManifest.hash;
1893
2309
  filenameTemplate = fileManifest.filenameTemplate;
2310
+ file = this.getPath(filenameTemplate, fileManifest.pathOptions);
2311
+
2312
+ // check if the same filename was already written by another chunk
2313
+ const alreadyWritten = alreadyWrittenFiles.get(file);
2314
+ if (alreadyWritten !== undefined) {
2315
+ if (alreadyWritten.hash === usedHash) {
2316
+ if (this.cache) {
2317
+ this.cache[cacheName] = {
2318
+ hash: usedHash,
2319
+ source: alreadyWritten.source
2320
+ };
2321
+ }
2322
+ chunk.files.push(file);
2323
+ this.hooks.chunkAsset.call(chunk, file);
2324
+ continue;
2325
+ } else {
2326
+ throw new Error(
2327
+ `Conflict: Multiple chunks emit assets to the same filename ${file}` +
2328
+ ` (chunks ${alreadyWritten.chunk.id} and ${chunk.id})`
2329
+ );
2330
+ }
2331
+ }
1894
2332
  if (
1895
2333
  this.cache &&
1896
2334
  this.cache[cacheName] &&
@@ -1917,7 +2355,6 @@ class Compilation extends Tapable {
1917
2355
  };
1918
2356
  }
1919
2357
  }
1920
- file = this.getPath(filenameTemplate, fileManifest.pathOptions);
1921
2358
  if (this.assets[file] && this.assets[file] !== source) {
1922
2359
  throw new Error(
1923
2360
  `Conflict: Multiple assets emit to the same filename ${file}`
@@ -1926,6 +2363,11 @@ class Compilation extends Tapable {
1926
2363
  this.assets[file] = source;
1927
2364
  chunk.files.push(file);
1928
2365
  this.hooks.chunkAsset.call(chunk, file);
2366
+ alreadyWrittenFiles.set(file, {
2367
+ hash: usedHash,
2368
+ source,
2369
+ chunk
2370
+ });
1929
2371
  }
1930
2372
  } catch (err) {
1931
2373
  this.errors.push(
@@ -1935,12 +2377,27 @@ class Compilation extends Tapable {
1935
2377
  }
1936
2378
  }
1937
2379
 
2380
+ /**
2381
+ * @param {string} filename used to get asset path with hash
2382
+ * @param {TODO=} data // TODO: figure out this param type
2383
+ * @returns {string} interpolated path
2384
+ */
1938
2385
  getPath(filename, data) {
1939
2386
  data = data || {};
1940
2387
  data.hash = data.hash || this.hash;
1941
2388
  return this.mainTemplate.getAssetPath(filename, data);
1942
2389
  }
1943
2390
 
2391
+ /**
2392
+ * This function allows you to run another instance of webpack inside of webpack however as
2393
+ * a child with different settings and configurations (if desired) applied. It copies all hooks, plugins
2394
+ * from parent (or top level compiler) and creates a child Compilation
2395
+ *
2396
+ * @param {string} name name of the child compiler
2397
+ * @param {TODO} outputOptions // Need to convert config schema to types for this
2398
+ * @param {Plugin[]} plugins webpack plugins that will be applied
2399
+ * @returns {Compiler} creates a child Compiler instance
2400
+ */
1944
2401
  createChildCompiler(name, outputOptions, plugins) {
1945
2402
  const idx = this.childrenCounters[name] || 0;
1946
2403
  this.childrenCounters[name] = idx + 1;
@@ -1954,6 +2411,7 @@ class Compilation extends Tapable {
1954
2411
  }
1955
2412
 
1956
2413
  checkConstraints() {
2414
+ /** @type {Set<number|string>} */
1957
2415
  const usedIds = new Set();
1958
2416
 
1959
2417
  const modules = this.modules;