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
@@ -6,6 +6,9 @@
6
6
  const ModuleDependency = require("./ModuleDependency");
7
7
 
8
8
  class LoaderDependency extends ModuleDependency {
9
+ /**
10
+ * @param {string} request request string
11
+ */
9
12
  constructor(request) {
10
13
  super(request);
11
14
  }
@@ -5,6 +5,17 @@
5
5
  "use strict";
6
6
 
7
7
  const LoaderDependency = require("./LoaderDependency");
8
+ const NormalModule = require("../NormalModule");
9
+
10
+ /** @typedef {import("../Module")} Module */
11
+
12
+ /**
13
+ * @callback LoadModuleCallback
14
+ * @param {Error=} err error object
15
+ * @param {string=} source source code
16
+ * @param {object=} map source map
17
+ * @param {Module=} module loaded module if successful
18
+ */
8
19
 
9
20
  class LoaderPlugin {
10
21
  apply(compiler) {
@@ -22,9 +33,16 @@ class LoaderPlugin {
22
33
  compilation.hooks.normalModuleLoader.tap(
23
34
  "LoaderPlugin",
24
35
  (loaderContext, module) => {
36
+ /**
37
+ * @param {string} request the request string to load the module from
38
+ * @param {LoadModuleCallback} callback callback returning the loaded module or error
39
+ * @returns {void}
40
+ */
25
41
  loaderContext.loadModule = (request, callback) => {
26
42
  const dep = new LoaderDependency(request);
27
- dep.loc = request;
43
+ dep.loc = {
44
+ name: request
45
+ };
28
46
  const factory = compilation.dependencyFactories.get(
29
47
  dep.constructor
30
48
  );
@@ -57,7 +75,8 @@ class LoaderPlugin {
57
75
  if (!dep.module) {
58
76
  return callback(new Error("Cannot load the module"));
59
77
  }
60
- if (dep.module.error) {
78
+ // TODO consider removing this in webpack 5
79
+ if (dep.module instanceof NormalModule && dep.module.error) {
61
80
  return callback(dep.module.error);
62
81
  }
63
82
  if (!dep.module._source) {
@@ -6,6 +6,9 @@
6
6
  const Dependency = require("../Dependency");
7
7
 
8
8
  class ModuleDependency extends Dependency {
9
+ /**
10
+ * @param {string} request request path which needs resolving
11
+ */
9
12
  constructor(request) {
10
13
  super();
11
14
  this.request = request;
@@ -3,9 +3,14 @@
3
3
  Author Tobias Koppers @sokra
4
4
  */
5
5
  "use strict";
6
+ /** @typedef {import("./SingleEntryDependency")} SingleEntryDependency */
6
7
  const Dependency = require("../Dependency");
7
8
 
8
9
  class MultiEntryDependency extends Dependency {
10
+ /**
11
+ * @param {SingleEntryDependency[]} dependencies an array of SingleEntryDependencies
12
+ * @param {string} name entry name
13
+ */
9
14
  constructor(dependencies, name) {
10
15
  super();
11
16
  this.dependencies = dependencies;
@@ -6,6 +6,9 @@
6
6
  const ModuleDependency = require("./ModuleDependency");
7
7
 
8
8
  class SingleEntryDependency extends ModuleDependency {
9
+ /**
10
+ * @param {string} request request path for entry
11
+ */
9
12
  constructor(request) {
10
13
  super(request);
11
14
  }
@@ -72,7 +72,7 @@ class SystemPlugin {
72
72
  parser.hooks.expression.for("System").tap("SystemPlugin", () => {
73
73
  const systemPolyfillRequire = ParserHelpers.requireFileAsExpression(
74
74
  parser.state.module.context,
75
- require.resolve("../../buildin/system.js")
75
+ require.resolve("../../buildin/system")
76
76
  );
77
77
  return ParserHelpers.addParsedVariableToModule(
78
78
  parser,
@@ -5,57 +5,71 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
9
+ /** @typedef {import("./Dependency").SourcePosition} SourcePosition */
10
+
11
+ // TODO webpack 5: pos must be SourcePosition
12
+ /**
13
+ * @param {SourcePosition|DependencyLocation|string} pos position
14
+ * @returns {string} formatted position
15
+ */
8
16
  const formatPosition = pos => {
9
17
  if (pos === null) return "";
10
- const typeOfPos = typeof pos;
11
- switch (typeOfPos) {
12
- case "string":
13
- return pos;
14
- case "number":
15
- return `${pos}`;
16
- case "object":
17
- if (typeof pos.line === "number" && typeof pos.column === "number") {
18
- return `${pos.line}:${pos.column}`;
19
- } else if (typeof pos.line === "number") {
20
- return `${pos.line}:?`;
21
- } else if (typeof pos.index === "number") {
22
- return `+${pos.index}`;
23
- } else {
24
- return "";
25
- }
26
- default:
18
+ // TODO webpack 5: Simplify this
19
+ if (typeof pos === "string") return pos;
20
+ if (typeof pos === "number") return `${pos}`;
21
+ if (typeof pos === "object") {
22
+ if ("line" in pos && "column" in pos) {
23
+ return `${pos.line}:${pos.column}`;
24
+ } else if ("line" in pos) {
25
+ return `${pos.line}:?`;
26
+ } else if ("index" in pos) {
27
+ // TODO webpack 5 remove this case
28
+ return `+${pos.index}`;
29
+ } else {
27
30
  return "";
31
+ }
28
32
  }
33
+ return "";
29
34
  };
30
35
 
36
+ // TODO webpack 5: loc must be DependencyLocation
37
+ /**
38
+ * @param {DependencyLocation|SourcePosition|string} loc location
39
+ * @returns {string} formatted location
40
+ */
31
41
  const formatLocation = loc => {
32
42
  if (loc === null) return "";
33
- const typeOfLoc = typeof loc;
34
- switch (typeOfLoc) {
35
- case "string":
36
- return loc;
37
- case "number":
38
- return `${loc}`;
39
- case "object":
40
- if (loc.start && loc.end) {
41
- if (
42
- typeof loc.start.line === "number" &&
43
- typeof loc.end.line === "number" &&
44
- typeof loc.end.column === "number" &&
45
- loc.start.line === loc.end.line
46
- ) {
47
- return `${formatPosition(loc.start)}-${loc.end.column}`;
48
- } else {
49
- return `${formatPosition(loc.start)}-${formatPosition(loc.end)}`;
50
- }
51
- }
52
- if (loc.start) {
53
- return formatPosition(loc.start);
43
+ // TODO webpack 5: Simplify this
44
+ if (typeof loc === "string") return loc;
45
+ if (typeof loc === "number") return `${loc}`;
46
+ if (typeof loc === "object") {
47
+ if ("start" in loc && loc.start && "end" in loc && loc.end) {
48
+ if (
49
+ typeof loc.start === "object" &&
50
+ typeof loc.start.line === "number" &&
51
+ typeof loc.end === "object" &&
52
+ typeof loc.end.line === "number" &&
53
+ typeof loc.end.column === "number" &&
54
+ loc.start.line === loc.end.line
55
+ ) {
56
+ return `${formatPosition(loc.start)}-${loc.end.column}`;
57
+ } else {
58
+ return `${formatPosition(loc.start)}-${formatPosition(loc.end)}`;
54
59
  }
55
- return formatPosition(loc);
56
- default:
57
- return "";
60
+ }
61
+ if ("start" in loc && loc.start) {
62
+ return formatPosition(loc.start);
63
+ }
64
+ if ("name" in loc && "index" in loc) {
65
+ return `${loc.name}[${loc.index}]`;
66
+ }
67
+ if ("name" in loc) {
68
+ return loc.name;
69
+ }
70
+ return formatPosition(loc);
58
71
  }
72
+ return "";
59
73
  };
60
74
 
61
75
  module.exports = formatLocation;
@@ -37,7 +37,7 @@ module.exports = function() {
37
37
  });
38
38
  }
39
39
 
40
- //eslint-disable-next-line no-unused-vars
40
+ // eslint-disable-next-line no-unused-vars
41
41
  function hotDisposeChunk(chunkId) {
42
42
  delete installedChunks[chunkId];
43
43
  }
@@ -305,8 +305,8 @@ module.exports = class NodeMainTemplatePlugin {
305
305
  );
306
306
  return Template.getFunctionContent(
307
307
  asyncChunkLoading
308
- ? require("./NodeMainTemplateAsync.runtime.js")
309
- : require("./NodeMainTemplate.runtime.js")
308
+ ? require("./NodeMainTemplateAsync.runtime")
309
+ : require("./NodeMainTemplate.runtime")
310
310
  )
311
311
  .replace(/\$require\$/g, mainTemplate.requireFn)
312
312
  .replace(/\$hotMainFilename\$/g, currentHotUpdateMainFilename)
@@ -71,7 +71,7 @@ module.exports = class NodeSourcePlugin {
71
71
  .tap("NodeSourcePlugin", () => {
72
72
  const retrieveGlobalModule = ParserHelpers.requireFileAsExpression(
73
73
  parser.state.module.context,
74
- require.resolve("../../buildin/global.js")
74
+ require.resolve("../../buildin/global")
75
75
  );
76
76
  return ParserHelpers.addParsedVariableToModule(
77
77
  parser,
@@ -20,6 +20,13 @@ const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibi
20
20
  const createHash = require("../util/createHash");
21
21
 
22
22
  /** @typedef {import("../Dependency")} Dependency */
23
+ /** @typedef {import("../Compilation")} Compilation */
24
+
25
+ /**
26
+ * @typedef {Object} ConcatenationEntry
27
+ * @property {"concatenated" | "external"} type
28
+ * @property {Module} module
29
+ */
23
30
 
24
31
  const ensureNsObjSource = (
25
32
  info,
@@ -125,6 +132,8 @@ const getFinalName = (
125
132
  requestShortener,
126
133
  strictHarmonyModule
127
134
  );
135
+ } else if (!info.module.isUsed(exportName)) {
136
+ return "/* unused export */ undefined";
128
137
  }
129
138
  const name = info.internalNames.get(directExport);
130
139
  if (!name) {
@@ -275,7 +284,7 @@ const getPathInAst = (ast, node) => {
275
284
  };
276
285
 
277
286
  class ConcatenatedModule extends Module {
278
- constructor(rootModule, modules) {
287
+ constructor(rootModule, modules, concatenationList) {
279
288
  super("javascript/esm", null);
280
289
  super.setChunks(rootModule._chunks);
281
290
 
@@ -320,10 +329,9 @@ class ConcatenatedModule extends Module {
320
329
 
321
330
  this.warnings = [];
322
331
  this.errors = [];
323
- this._orderedConcatenationList = this._createOrderedConcatenationList(
324
- rootModule,
325
- modulesSet
326
- );
332
+ this._orderedConcatenationList =
333
+ concatenationList ||
334
+ ConcatenatedModule.createConcatenationList(rootModule, modulesSet, null);
327
335
  for (const info of this._orderedConcatenationList) {
328
336
  if (info.type === "concatenated") {
329
337
  const m = info.module;
@@ -410,7 +418,13 @@ class ConcatenatedModule extends Module {
410
418
  }, 0);
411
419
  }
412
420
 
413
- _createOrderedConcatenationList(rootModule, modulesSet) {
421
+ /**
422
+ * @param {Module} rootModule the root of the concatenation
423
+ * @param {Set<Module>} modulesSet a set of modules which should be concatenated
424
+ * @param {Compilation} compilation the compilation context
425
+ * @returns {ConcatenationEntry[]} concatenation list
426
+ */
427
+ static createConcatenationList(rootModule, modulesSet, compilation) {
414
428
  const list = [];
415
429
  const set = new Set();
416
430
 
@@ -424,15 +438,16 @@ class ConcatenatedModule extends Module {
424
438
  const references = module.dependencies
425
439
  .filter(dep => dep instanceof HarmonyImportDependency)
426
440
  .map(dep => {
427
- const ref = dep.getReference();
441
+ const ref = compilation.getDependencyReference(module, dep);
428
442
  if (ref) map.set(ref, dep);
429
443
  return ref;
430
444
  })
431
445
  .filter(ref => ref);
432
446
  DependencyReference.sort(references);
447
+ // TODO webpack 5: remove this hack, see also DependencyReference
433
448
  return references.map(ref => {
434
449
  const dep = map.get(ref);
435
- return () => dep.getReference().module;
450
+ return () => compilation.getDependencyReference(module, dep).module;
436
451
  });
437
452
  };
438
453
 
@@ -624,6 +639,7 @@ class ConcatenatedModule extends Module {
624
639
 
625
640
  // Must use full identifier in our cache here to ensure that the source
626
641
  // is updated should our dependencies list change.
642
+ // TODO webpack 5 refactor
627
643
  innerDependencyTemplates.set(
628
644
  "hash",
629
645
  innerDependencyTemplates.get("hash") + this.identifier()
@@ -213,8 +213,9 @@ class ModuleConcatenationPlugin {
213
213
  const failureCache = new Map();
214
214
 
215
215
  // try to add all imports
216
- for (const imp of this.getImports(currentRoot)) {
217
- const problem = this.tryToAdd(
216
+ for (const imp of this._getImports(compilation, currentRoot)) {
217
+ const problem = this._tryToAdd(
218
+ compilation,
218
219
  currentConfiguration,
219
220
  imp,
220
221
  possibleInners,
@@ -245,9 +246,15 @@ class ModuleConcatenationPlugin {
245
246
  for (const concatConfiguration of concatConfigurations) {
246
247
  if (usedModules.has(concatConfiguration.rootModule)) continue;
247
248
  const modules = concatConfiguration.getModules();
249
+ const rootModule = concatConfiguration.rootModule;
248
250
  const newModule = new ConcatenatedModule(
249
- concatConfiguration.rootModule,
250
- modules
251
+ rootModule,
252
+ Array.from(modules),
253
+ ConcatenatedModule.createConcatenationList(
254
+ rootModule,
255
+ modules,
256
+ compilation
257
+ )
251
258
  );
252
259
  for (const warning of concatConfiguration.getWarningsSorted()) {
253
260
  newModule.optimizationBailout.push(requestShortener => {
@@ -320,15 +327,16 @@ class ModuleConcatenationPlugin {
320
327
  );
321
328
  }
322
329
 
323
- getImports(module) {
330
+ _getImports(compilation, module) {
324
331
  return new Set(
325
332
  module.dependencies
326
333
 
327
334
  // Get reference info only for harmony Dependencies
328
- .map(
329
- dep =>
330
- dep instanceof HarmonyImportDependency ? dep.getReference() : null
331
- )
335
+ .map(dep => {
336
+ if (!(dep instanceof HarmonyImportDependency)) return null;
337
+ if (!compilation) return dep.getReference();
338
+ return compilation.getDependencyReference(module, dep);
339
+ })
332
340
 
333
341
  // Reference is valid and has a module
334
342
  // Dependencies are simple enough to concat them
@@ -345,7 +353,7 @@ class ModuleConcatenationPlugin {
345
353
  );
346
354
  }
347
355
 
348
- tryToAdd(config, module, possibleModules, failureCache) {
356
+ _tryToAdd(compilation, config, module, possibleModules, failureCache) {
349
357
  const cacheEntry = failureCache.get(module);
350
358
  if (cacheEntry) {
351
359
  return cacheEntry;
@@ -383,7 +391,8 @@ class ModuleConcatenationPlugin {
383
391
  )
384
392
  continue;
385
393
 
386
- const problem = this.tryToAdd(
394
+ const problem = this._tryToAdd(
395
+ compilation,
387
396
  testConfig,
388
397
  reason.module,
389
398
  possibleModules,
@@ -399,8 +408,14 @@ class ModuleConcatenationPlugin {
399
408
  config.set(testConfig);
400
409
 
401
410
  // Eagerly try to add imports too if possible
402
- for (const imp of this.getImports(module)) {
403
- const problem = this.tryToAdd(config, imp, possibleModules, failureCache);
411
+ for (const imp of this._getImports(compilation, module)) {
412
+ const problem = this._tryToAdd(
413
+ compilation,
414
+ config,
415
+ imp,
416
+ possibleModules,
417
+ failureCache
418
+ );
404
419
  if (problem) {
405
420
  config.addWarning(imp, problem);
406
421
  }
@@ -451,7 +466,7 @@ class ConcatConfiguration {
451
466
  }
452
467
 
453
468
  getModules() {
454
- return this.modules.asArray();
469
+ return this.modules.asSet();
455
470
  }
456
471
 
457
472
  clone() {
@@ -0,0 +1,41 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ "use strict";
6
+
7
+ /** @typedef {import("../Compiler")} Compiler */
8
+
9
+ class NaturalChunkOrderPlugin {
10
+ /**
11
+ * @param {Compiler} compiler webpack compiler
12
+ * @returns {void}
13
+ */
14
+ apply(compiler) {
15
+ compiler.hooks.compilation.tap("NaturalChunkOrderPlugin", compilation => {
16
+ compilation.hooks.optimizeChunkOrder.tap(
17
+ "NaturalChunkOrderPlugin",
18
+ chunks => {
19
+ chunks.sort((chunkA, chunkB) => {
20
+ const a = chunkA.modulesIterable[Symbol.iterator]();
21
+ const b = chunkB.modulesIterable[Symbol.iterator]();
22
+ // eslint-disable-next-line no-constant-condition
23
+ while (true) {
24
+ const aItem = a.next();
25
+ const bItem = b.next();
26
+ if (aItem.done && bItem.done) return 0;
27
+ if (aItem.done) return -1;
28
+ if (bItem.done) return 1;
29
+ const aModuleId = aItem.value.id;
30
+ const bModuleId = bItem.value.id;
31
+ if (aModuleId < bModuleId) return -1;
32
+ if (aModuleId > bModuleId) return 1;
33
+ }
34
+ });
35
+ }
36
+ );
37
+ });
38
+ }
39
+ }
40
+
41
+ module.exports = NaturalChunkOrderPlugin;
@@ -0,0 +1,61 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ "use strict";
6
+
7
+ const validateOptions = require("schema-utils");
8
+ const schema = require("../../schemas/plugins/optimize/OccurrenceOrderChunkIdsPlugin.json");
9
+
10
+ class OccurrenceOrderChunkIdsPlugin {
11
+ constructor(options = {}) {
12
+ validateOptions(schema, options, "Occurrence Order Chunk Ids Plugin");
13
+ this.options = options;
14
+ }
15
+
16
+ apply(compiler) {
17
+ const prioritiseInitial = this.options.prioritiseInitial;
18
+ compiler.hooks.compilation.tap(
19
+ "OccurrenceOrderChunkIdsPlugin",
20
+ compilation => {
21
+ compilation.hooks.optimizeChunkOrder.tap(
22
+ "OccurrenceOrderChunkIdsPlugin",
23
+ chunks => {
24
+ const occursInInitialChunksMap = new Map();
25
+ const originalOrder = new Map();
26
+
27
+ let i = 0;
28
+ for (const c of chunks) {
29
+ let occurs = 0;
30
+ for (const chunkGroup of c.groupsIterable) {
31
+ for (const parent of chunkGroup.parentsIterable) {
32
+ if (parent.isInitial()) occurs++;
33
+ }
34
+ }
35
+ occursInInitialChunksMap.set(c, occurs);
36
+ originalOrder.set(c, i++);
37
+ }
38
+
39
+ chunks.sort((a, b) => {
40
+ if (prioritiseInitial) {
41
+ const aEntryOccurs = occursInInitialChunksMap.get(a);
42
+ const bEntryOccurs = occursInInitialChunksMap.get(b);
43
+ if (aEntryOccurs > bEntryOccurs) return -1;
44
+ if (aEntryOccurs < bEntryOccurs) return 1;
45
+ }
46
+ const aOccurs = a.getNumberOfGroups();
47
+ const bOccurs = b.getNumberOfGroups();
48
+ if (aOccurs > bOccurs) return -1;
49
+ if (aOccurs < bOccurs) return 1;
50
+ const orgA = originalOrder.get(a);
51
+ const orgB = originalOrder.get(b);
52
+ return orgB - orgA;
53
+ });
54
+ }
55
+ );
56
+ }
57
+ );
58
+ }
59
+ }
60
+
61
+ module.exports = OccurrenceOrderChunkIdsPlugin;
@@ -0,0 +1,103 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+ "use strict";
6
+
7
+ const validateOptions = require("schema-utils");
8
+ const schema = require("../../schemas/plugins/optimize/OccurrenceOrderModuleIdsPlugin.json");
9
+
10
+ class OccurrenceOrderModuleIdsPlugin {
11
+ constructor(options = {}) {
12
+ validateOptions(schema, options, "Occurrence Order Module Ids Plugin");
13
+ this.options = options;
14
+ }
15
+
16
+ apply(compiler) {
17
+ const prioritiseInitial = this.options.prioritiseInitial;
18
+ compiler.hooks.compilation.tap(
19
+ "OccurrenceOrderModuleIdsPlugin",
20
+ compilation => {
21
+ compilation.hooks.optimizeModuleOrder.tap(
22
+ "OccurrenceOrderModuleIdsPlugin",
23
+ modules => {
24
+ const occursInInitialChunksMap = new Map();
25
+ const occursInAllChunksMap = new Map();
26
+
27
+ const initialChunkChunkMap = new Map();
28
+ const entryCountMap = new Map();
29
+ for (const m of modules) {
30
+ let initial = 0;
31
+ let entry = 0;
32
+ for (const c of m.chunksIterable) {
33
+ if (c.canBeInitial()) initial++;
34
+ if (c.entryModule === m) entry++;
35
+ }
36
+ initialChunkChunkMap.set(m, initial);
37
+ entryCountMap.set(m, entry);
38
+ }
39
+
40
+ const countOccursInEntry = (sum, r) => {
41
+ if (!r.module) {
42
+ return sum;
43
+ }
44
+ return sum + initialChunkChunkMap.get(r.module);
45
+ };
46
+ const countOccurs = (sum, r) => {
47
+ if (!r.module) {
48
+ return sum;
49
+ }
50
+ let factor = 1;
51
+ if (typeof r.dependency.getNumberOfIdOccurrences === "function") {
52
+ factor = r.dependency.getNumberOfIdOccurrences();
53
+ }
54
+ if (factor === 0) {
55
+ return sum;
56
+ }
57
+ return sum + factor * r.module.getNumberOfChunks();
58
+ };
59
+
60
+ if (prioritiseInitial) {
61
+ for (const m of modules) {
62
+ const result =
63
+ m.reasons.reduce(countOccursInEntry, 0) +
64
+ initialChunkChunkMap.get(m) +
65
+ entryCountMap.get(m);
66
+ occursInInitialChunksMap.set(m, result);
67
+ }
68
+ }
69
+
70
+ const originalOrder = new Map();
71
+ let i = 0;
72
+ for (const m of modules) {
73
+ const result =
74
+ m.reasons.reduce(countOccurs, 0) +
75
+ m.getNumberOfChunks() +
76
+ entryCountMap.get(m);
77
+ occursInAllChunksMap.set(m, result);
78
+ originalOrder.set(m, i++);
79
+ }
80
+
81
+ modules.sort((a, b) => {
82
+ if (prioritiseInitial) {
83
+ const aEntryOccurs = occursInInitialChunksMap.get(a);
84
+ const bEntryOccurs = occursInInitialChunksMap.get(b);
85
+ if (aEntryOccurs > bEntryOccurs) return -1;
86
+ if (aEntryOccurs < bEntryOccurs) return 1;
87
+ }
88
+ const aOccurs = occursInAllChunksMap.get(a);
89
+ const bOccurs = occursInAllChunksMap.get(b);
90
+ if (aOccurs > bOccurs) return -1;
91
+ if (aOccurs < bOccurs) return 1;
92
+ const orgA = originalOrder.get(a);
93
+ const orgB = originalOrder.get(b);
94
+ return orgB - orgA;
95
+ });
96
+ }
97
+ );
98
+ }
99
+ );
100
+ }
101
+ }
102
+
103
+ module.exports = OccurrenceOrderModuleIdsPlugin;
@@ -4,6 +4,8 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ // TODO webpack 5 remove this plugin
8
+ // It has been splitted into separate plugins for modules and chunks
7
9
  class OccurrenceOrderPlugin {
8
10
  constructor(preferEntry) {
9
11
  if (preferEntry !== undefined && typeof preferEntry !== "boolean") {