webpack 5.90.0 → 5.90.2

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.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

Files changed (38) hide show
  1. package/lib/APIPlugin.js +16 -12
  2. package/lib/Compilation.js +1 -1
  3. package/lib/ConditionalInitFragment.js +3 -3
  4. package/lib/DefinePlugin.js +47 -26
  5. package/lib/EvalSourceMapDevToolPlugin.js +1 -1
  6. package/lib/InitFragment.js +7 -7
  7. package/lib/NodeStuffPlugin.js +3 -3
  8. package/lib/Stats.js +4 -0
  9. package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
  10. package/lib/buildChunkGraph.js +101 -15
  11. package/lib/config/browserslistTargetHandler.js +18 -16
  12. package/lib/config/defaults.js +1 -0
  13. package/lib/dependencies/AMDDefineDependency.js +4 -4
  14. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +126 -34
  15. package/lib/dependencies/AMDPlugin.js +11 -4
  16. package/lib/dependencies/AMDRequireArrayDependency.js +13 -1
  17. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +159 -43
  18. package/lib/dependencies/AMDRequireDependency.js +2 -2
  19. package/lib/dependencies/AMDRequireItemDependency.js +1 -1
  20. package/lib/dependencies/ExportsInfoDependency.js +6 -12
  21. package/lib/dependencies/ExternalModuleDependency.js +9 -0
  22. package/lib/dependencies/ExternalModuleInitFragment.js +10 -3
  23. package/lib/dependencies/HarmonyExportInitFragment.js +2 -2
  24. package/lib/dependencies/HarmonyImportSpecifierDependency.js +1 -1
  25. package/lib/dependencies/ImportParserPlugin.js +1 -0
  26. package/lib/dependencies/LocalModuleDependency.js +1 -1
  27. package/lib/dependencies/WorkerPlugin.js +3 -2
  28. package/lib/dependencies/getFunctionExpression.js +2 -2
  29. package/lib/hmr/HotModuleReplacement.runtime.js +1 -1
  30. package/lib/javascript/JavascriptParser.js +212 -74
  31. package/lib/optimize/MangleExportsPlugin.js +5 -1
  32. package/lib/runtime/AutoPublicPathRuntimeModule.js +1 -1
  33. package/lib/util/chainedImports.js +7 -6
  34. package/lib/util/comparators.js +59 -23
  35. package/lib/util/numberHash.js +53 -52
  36. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +53 -28
  37. package/package.json +4 -59
  38. package/types.d.ts +101 -74
package/lib/APIPlugin.js CHANGED
@@ -24,10 +24,12 @@ const ChunkNameRuntimeModule = require("./runtime/ChunkNameRuntimeModule");
24
24
  const GetFullHashRuntimeModule = require("./runtime/GetFullHashRuntimeModule");
25
25
 
26
26
  /** @typedef {import("./Compiler")} Compiler */
27
+ /** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
27
28
  /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
29
+ /** @typedef {import("./javascript/JavascriptParser").Range} Range */
28
30
 
29
31
  /**
30
- * @param {boolean} module true if ES module
32
+ * @param {boolean | undefined} module true if ES module
31
33
  * @param {string} importMetaName `import.meta` name
32
34
  * @returns {Record<string, {expr: string, req: string[] | null, type?: string, assign: boolean}>} replacements
33
35
  */
@@ -150,7 +152,9 @@ class APIPlugin {
150
152
  compiler.hooks.compilation.tap(
151
153
  PLUGIN_NAME,
152
154
  (compilation, { normalModuleFactory }) => {
153
- const { importMetaName } = compilation.outputOptions;
155
+ const importMetaName = /** @type {string} */ (
156
+ compilation.outputOptions.importMetaName
157
+ );
154
158
  const REPLACEMENTS = getReplacements(
155
159
  this.options.module,
156
160
  importMetaName
@@ -166,7 +170,7 @@ class APIPlugin {
166
170
  .tap(PLUGIN_NAME, chunk => {
167
171
  compilation.addRuntimeModule(
168
172
  chunk,
169
- new ChunkNameRuntimeModule(chunk.name)
173
+ new ChunkNameRuntimeModule(/** @type {string} */ (chunk.name))
170
174
  );
171
175
  return true;
172
176
  });
@@ -218,7 +222,7 @@ class APIPlugin {
218
222
  if (info.assign === false) {
219
223
  parser.hooks.assign.for(key).tap(PLUGIN_NAME, expr => {
220
224
  const err = new WebpackError(`${key} must not be assigned`);
221
- err.loc = expr.loc;
225
+ err.loc = /** @type {DependencyLocation} */ (expr.loc);
222
226
  throw err;
223
227
  });
224
228
  }
@@ -234,9 +238,9 @@ class APIPlugin {
234
238
  .tap(PLUGIN_NAME, expr => {
235
239
  const dep = new ConstDependency(
236
240
  JSON.stringify(parser.state.module.layer),
237
- expr.range
241
+ /** @type {Range} */ (expr.range)
238
242
  );
239
- dep.loc = expr.loc;
243
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
240
244
  parser.state.module.addPresentationalDependency(dep);
241
245
  return true;
242
246
  });
@@ -248,7 +252,7 @@ class APIPlugin {
248
252
  : new BasicEvaluatedExpression().setString(
249
253
  parser.state.module.layer
250
254
  )
251
- ).setRange(expr.range)
255
+ ).setRange(/** @type {Range} */ (expr.range))
252
256
  );
253
257
  parser.hooks.evaluateTypeof
254
258
  .for("__webpack_layer__")
@@ -257,7 +261,7 @@ class APIPlugin {
257
261
  .setString(
258
262
  parser.state.module.layer === null ? "object" : "string"
259
263
  )
260
- .setRange(expr.range)
264
+ .setRange(/** @type {Range} */ (expr.range))
261
265
  );
262
266
 
263
267
  parser.hooks.expression
@@ -267,10 +271,10 @@ class APIPlugin {
267
271
  "__webpack_module__.id";
268
272
  const dep = new ConstDependency(
269
273
  parser.state.module.moduleArgument + ".id",
270
- expr.range,
274
+ /** @type {Range} */ (expr.range),
271
275
  [RuntimeGlobals.moduleId]
272
276
  );
273
- dep.loc = expr.loc;
277
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
274
278
  parser.state.module.addPresentationalDependency(dep);
275
279
  return true;
276
280
  });
@@ -282,10 +286,10 @@ class APIPlugin {
282
286
  "__webpack_module__";
283
287
  const dep = new ConstDependency(
284
288
  parser.state.module.moduleArgument,
285
- expr.range,
289
+ /** @type {Range} */ (expr.range),
286
290
  [RuntimeGlobals.module]
287
291
  );
288
- dep.loc = expr.loc;
292
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
289
293
  parser.state.module.addPresentationalDependency(dep);
290
294
  return true;
291
295
  });
@@ -1087,7 +1087,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
1087
1087
  }
1088
1088
 
1089
1089
  /**
1090
- * @param {StatsOptions | string} optionsOrPreset stats option value
1090
+ * @param {StatsOptions | string | undefined} optionsOrPreset stats option value
1091
1091
  * @param {CreateStatsOptionsContext} context context
1092
1092
  * @returns {NormalizedStatsOptions} normalized options
1093
1093
  */
@@ -62,8 +62,8 @@ class ConditionalInitFragment extends InitFragment {
62
62
  }
63
63
 
64
64
  /**
65
- * @param {Context} context context
66
- * @returns {string|Source} the source code that will be included as initialization code
65
+ * @param {GenerateContext} context context
66
+ * @returns {string | Source} the source code that will be included as initialization code
67
67
  */
68
68
  getContent(context) {
69
69
  if (this.runtimeCondition === false || !this.content) return "";
@@ -79,7 +79,7 @@ class ConditionalInitFragment extends InitFragment {
79
79
  }
80
80
 
81
81
  /**
82
- * @param {Context} context context
82
+ * @param {GenerateContext} context context
83
83
  * @returns {string|Source=} the source code that will be included at the end of the module
84
84
  */
85
85
  getEndContent(context) {
@@ -23,9 +23,11 @@ const createHash = require("./util/createHash");
23
23
 
24
24
  /** @typedef {import("estree").Expression} Expression */
25
25
  /** @typedef {import("./Compiler")} Compiler */
26
+ /** @typedef {import("./Module").BuildInfo} BuildInfo */
26
27
  /** @typedef {import("./NormalModule")} NormalModule */
27
28
  /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
28
29
  /** @typedef {import("./javascript/JavascriptParser")} JavascriptParser */
30
+ /** @typedef {import("./javascript/JavascriptParser").Range} Range */
29
31
  /** @typedef {import("./logging/Logger").Logger} Logger */
30
32
 
31
33
  /** @typedef {null|undefined|RegExp|Function|string|number|boolean|bigint|undefined} CodeValuePrimitive */
@@ -66,7 +68,7 @@ class RuntimeValue {
66
68
  * @returns {CodeValuePrimitive} code
67
69
  */
68
70
  exec(parser, valueCacheVersions, key) {
69
- const buildInfo = parser.state.module.buildInfo;
71
+ const buildInfo = /** @type {BuildInfo} */ (parser.state.module.buildInfo);
70
72
  if (this.options === true) {
71
73
  buildInfo.cacheable = false;
72
74
  } else {
@@ -136,19 +138,21 @@ const stringifyObj = (
136
138
  let code;
137
139
  let arr = Array.isArray(obj);
138
140
  if (arr) {
139
- code = `[${obj
140
- .map(code =>
141
- toCode(
142
- code,
143
- parser,
144
- valueCacheVersions,
145
- key,
146
- runtimeTemplate,
147
- logger,
148
- null
141
+ code = `[${
142
+ /** @type {any[]} */ (obj)
143
+ .map(code =>
144
+ toCode(
145
+ code,
146
+ parser,
147
+ valueCacheVersions,
148
+ key,
149
+ runtimeTemplate,
150
+ logger,
151
+ null
152
+ )
149
153
  )
150
- )
151
- .join(",")}]`;
154
+ .join(",")
155
+ }]`;
152
156
  } else {
153
157
  let keys = Object.keys(obj);
154
158
  if (objKeys) {
@@ -157,7 +161,7 @@ const stringifyObj = (
157
161
  }
158
162
  code = `{${keys
159
163
  .map(key => {
160
- const code = obj[key];
164
+ const code = /** @type {{[k: string]: any}} */ (obj)[key];
161
165
  return (
162
166
  JSON.stringify(key) +
163
167
  ":" +
@@ -263,6 +267,10 @@ const toCode = (
263
267
  return strCode;
264
268
  };
265
269
 
270
+ /**
271
+ * @param {CodeValue} code code
272
+ * @returns {string | undefined} result
273
+ */
266
274
  const toCacheVersion = code => {
267
275
  if (code === null) {
268
276
  return "null";
@@ -285,7 +293,7 @@ const toCacheVersion = code => {
285
293
  if (typeof code === "object") {
286
294
  const items = Object.keys(code).map(key => ({
287
295
  key,
288
- value: toCacheVersion(code[key])
296
+ value: toCacheVersion(/** @type {Record<string, any>} */ (code)[key])
289
297
  }));
290
298
  if (items.some(({ value }) => value === undefined)) return undefined;
291
299
  return `{${items.map(({ key, value }) => `${key}: ${value}`).join(", ")}}`;
@@ -353,14 +361,21 @@ class DefinePlugin {
353
361
  const handler = parser => {
354
362
  const mainValue = compilation.valueCacheVersions.get(VALUE_DEP_MAIN);
355
363
  parser.hooks.program.tap(PLUGIN_NAME, () => {
356
- const { buildInfo } = parser.state.module;
364
+ const buildInfo = /** @type {BuildInfo} */ (
365
+ parser.state.module.buildInfo
366
+ );
357
367
  if (!buildInfo.valueDependencies)
358
368
  buildInfo.valueDependencies = new Map();
359
369
  buildInfo.valueDependencies.set(VALUE_DEP_MAIN, mainValue);
360
370
  });
361
371
 
372
+ /**
373
+ * @param {string} key key
374
+ */
362
375
  const addValueDependency = key => {
363
- const { buildInfo } = parser.state.module;
376
+ const buildInfo = /** @type {BuildInfo} */ (
377
+ parser.state.module.buildInfo
378
+ );
364
379
  buildInfo.valueDependencies.set(
365
380
  VALUE_DEP_PREFIX + key,
366
381
  compilation.valueCacheVersions.get(VALUE_DEP_PREFIX + key)
@@ -376,7 +391,7 @@ class DefinePlugin {
376
391
 
377
392
  /**
378
393
  * Walk definitions
379
- * @param {Object} definitions Definitions map
394
+ * @param {Record<string, CodeValue>} definitions Definitions map
380
395
  * @param {string} prefix Prefix string
381
396
  * @returns {void}
382
397
  */
@@ -389,7 +404,10 @@ class DefinePlugin {
389
404
  !(code instanceof RuntimeValue) &&
390
405
  !(code instanceof RegExp)
391
406
  ) {
392
- walkDefinitions(code, prefix + key + ".");
407
+ walkDefinitions(
408
+ /** @type {Record<string, CodeValue>} */ (code),
409
+ prefix + key + "."
410
+ );
393
411
  applyObjectDefine(prefix + key, code);
394
412
  return;
395
413
  }
@@ -458,7 +476,7 @@ class DefinePlugin {
458
476
  )
459
477
  );
460
478
  recurse = false;
461
- res.setRange(expr.range);
479
+ res.setRange(/** @type {Range} */ (expr.range));
462
480
  return res;
463
481
  });
464
482
  parser.hooks.expression.for(key).tap(PLUGIN_NAME, expr => {
@@ -470,7 +488,7 @@ class DefinePlugin {
470
488
  originalKey,
471
489
  runtimeTemplate,
472
490
  logger,
473
- !parser.isAsiPosition(expr.range[0]),
491
+ !parser.isAsiPosition(/** @type {Range} */ (expr.range)[0]),
474
492
  parser.destructuringAssignmentPropertiesFor(expr)
475
493
  );
476
494
 
@@ -517,7 +535,7 @@ class DefinePlugin {
517
535
  : "typeof (" + codeCode + ")";
518
536
  const res = parser.evaluate(typeofCode);
519
537
  recurseTypeof = false;
520
- res.setRange(expr.range);
538
+ res.setRange(/** @type {Range} */ (expr.range));
521
539
  return res;
522
540
  });
523
541
  parser.hooks.typeof.for(key).tap(PLUGIN_NAME, expr => {
@@ -559,7 +577,7 @@ class DefinePlugin {
559
577
  return new BasicEvaluatedExpression()
560
578
  .setTruthy()
561
579
  .setSideEffects(false)
562
- .setRange(expr.range);
580
+ .setRange(/** @type {Range} */ (expr.range));
563
581
  });
564
582
  parser.hooks.evaluateTypeof
565
583
  .for(key)
@@ -576,7 +594,7 @@ class DefinePlugin {
576
594
  key,
577
595
  runtimeTemplate,
578
596
  logger,
579
- !parser.isAsiPosition(expr.range[0]),
597
+ !parser.isAsiPosition(/** @type {Range} */ (expr.range)[0]),
580
598
  parser.destructuringAssignmentPropertiesFor(expr)
581
599
  );
582
600
 
@@ -622,7 +640,7 @@ class DefinePlugin {
622
640
 
623
641
  /**
624
642
  * Walk definitions
625
- * @param {Object} definitions Definitions map
643
+ * @param {Record<string, CodeValue>} definitions Definitions map
626
644
  * @param {string} prefix Prefix string
627
645
  * @returns {void}
628
646
  */
@@ -649,7 +667,10 @@ class DefinePlugin {
649
667
  !(code instanceof RuntimeValue) &&
650
668
  !(code instanceof RegExp)
651
669
  ) {
652
- walkDefinitionsForValues(code, prefix + key + ".");
670
+ walkDefinitionsForValues(
671
+ /** @type {Record<string, CodeValue>} */ (code),
672
+ prefix + key + "."
673
+ );
653
674
  }
654
675
  });
655
676
  };
@@ -129,7 +129,7 @@ class EvalSourceMapDevToolPlugin {
129
129
 
130
130
  // Clone (flat) the sourcemap to ensure that the mutations below do not persist.
131
131
  sourceMap = { ...sourceMap };
132
- const context = compiler.options.context;
132
+ const context = /** @type {string} */ (compiler.options.context);
133
133
  const root = compiler.root;
134
134
  const modules = sourceMap.sources.map(source => {
135
135
  if (!source.startsWith("webpack://")) return source;
@@ -36,15 +36,15 @@ const sortFragmentWithIndex = ([a, i], [b, j]) => {
36
36
  };
37
37
 
38
38
  /**
39
- * @template Context
39
+ * @template GenerateContext
40
40
  */
41
41
  class InitFragment {
42
42
  /**
43
- * @param {string|Source} content the source code that will be included as initialization code
43
+ * @param {string | Source} content the source code that will be included as initialization code
44
44
  * @param {number} stage category of initialization code (contribute to order)
45
45
  * @param {number} position position in the category (contribute to order)
46
46
  * @param {string=} key unique key to avoid emitting the same initialization code twice
47
- * @param {string|Source=} endContent the source code that will be included at the end of the module
47
+ * @param {string | Source=} endContent the source code that will be included at the end of the module
48
48
  */
49
49
  constructor(content, stage, position, key, endContent) {
50
50
  this.content = content;
@@ -55,15 +55,15 @@ class InitFragment {
55
55
  }
56
56
 
57
57
  /**
58
- * @param {Context} context context
59
- * @returns {string|Source} the source code that will be included as initialization code
58
+ * @param {GenerateContext} context context
59
+ * @returns {string | Source} the source code that will be included as initialization code
60
60
  */
61
61
  getContent(context) {
62
62
  return this.content;
63
63
  }
64
64
 
65
65
  /**
66
- * @param {Context} context context
66
+ * @param {GenerateContext} context context
67
67
  * @returns {string|Source=} the source code that will be included at the end of the module
68
68
  */
69
69
  getEndContent(context) {
@@ -91,7 +91,7 @@ class InitFragment {
91
91
  for (const [fragment] of sortedFragments) {
92
92
  if (
93
93
  typeof (
94
- /** @type {InitFragment<T> & { mergeAll?: (fragments: InitFragment[]) => InitFragment[] }} */
94
+ /** @type {InitFragment<T> & { mergeAll?: (fragments: InitFragment<Context>[]) => InitFragment<Context>[] }} */
95
95
  (fragment).mergeAll
96
96
  ) === "function"
97
97
  ) {
@@ -136,7 +136,7 @@ class NodeStuffPlugin {
136
136
 
137
137
  /**
138
138
  * @param {string} expressionName expression name
139
- * @param {(value: string) => void} fn function
139
+ * @param {(value: string) => string} fn function
140
140
  * @returns {void}
141
141
  */
142
142
  const setUrlModuleConstant = (expressionName, fn) => {
@@ -153,10 +153,10 @@ class NodeStuffPlugin {
153
153
  ],
154
154
  undefined,
155
155
  fn("__webpack_fileURLToPath__"),
156
- expr.range,
156
+ /** @type {Range} */ (expr.range),
157
157
  expressionName
158
158
  );
159
- dep.loc = expr.loc;
159
+ dep.loc = /** @type {DependencyLocation} */ (expr.loc);
160
160
  parser.state.module.addPresentationalDependency(dep);
161
161
 
162
162
  return true;
package/lib/Stats.js CHANGED
@@ -65,6 +65,10 @@ class Stats {
65
65
  });
66
66
  }
67
67
 
68
+ /**
69
+ * @param {(string|StatsOptions)=} options stats options
70
+ * @returns {string} string output
71
+ */
68
72
  toString(options) {
69
73
  options = this.compilation.createStatsOptions(options, {
70
74
  forToString: true
@@ -42,8 +42,8 @@ class AwaitDependenciesInitFragment extends InitFragment {
42
42
  }
43
43
 
44
44
  /**
45
- * @param {Context} context context
46
- * @returns {string|Source} the source code that will be included as initialization code
45
+ * @param {GenerateContext} context context
46
+ * @returns {string | Source} the source code that will be included as initialization code
47
47
  */
48
48
  getContent({ runtimeRequirements }) {
49
49
  runtimeRequirements.add(RuntimeGlobals.module);
@@ -44,7 +44,7 @@ const { getEntryRuntime, mergeRuntime } = require("./util/runtime");
44
44
  * @property {boolean | undefined} minAvailableModulesOwned true, if minAvailableModules is owned and can be modified
45
45
  * @property {ModuleSetPlus[]} availableModulesToBeMerged enqueued updates to the minimal set of available modules
46
46
  * @property {Set<Module>=} skippedItems modules that were skipped because module is already available in parent chunks (need to reconsider when minAvailableModules is shrinking)
47
- * @property {Set<[Module, ConnectionState]>=} skippedModuleConnections referenced modules that where skipped because they were not active in this runtime
47
+ * @property {Set<[Module, ModuleGraphConnection[]]>=} skippedModuleConnections referenced modules that where skipped because they were not active in this runtime
48
48
  * @property {ModuleSetPlus | undefined} resultingAvailableModules set of modules available including modules from this chunk group
49
49
  * @property {Set<ChunkGroupInfo> | undefined} children set of children chunk groups, that will be revisited when availableModules shrink
50
50
  * @property {Set<ChunkGroupInfo> | undefined} availableSources set of chunk groups that are the source for minAvailableModules
@@ -73,6 +73,25 @@ const bySetSize = (a, b) => {
73
73
  return b.size + b.plus.size - a.size - a.plus.size;
74
74
  };
75
75
 
76
+ /**
77
+ * @param {ModuleGraphConnection[]} connections list of connections
78
+ * @param {RuntimeSpec} runtime for which runtime
79
+ * @returns {ConnectionState} connection state
80
+ */
81
+ const getActiveStateOfConnections = (connections, runtime) => {
82
+ let merged = connections[0].getActiveState(runtime);
83
+ if (merged === true) return true;
84
+ for (let i = 1; i < connections.length; i++) {
85
+ const c = connections[i];
86
+ merged = ModuleGraphConnection.addConnectionStates(
87
+ merged,
88
+ c.getActiveState(runtime)
89
+ );
90
+ if (merged === true) return true;
91
+ }
92
+ return merged;
93
+ };
94
+
76
95
  const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
77
96
  let blockCache;
78
97
  let modules;
@@ -99,9 +118,6 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
99
118
  if (!m) continue;
100
119
  // We skip weak connections
101
120
  if (connection.weak) continue;
102
- const state = connection.getActiveState(runtime);
103
- // We skip inactive connections
104
- if (state === false) continue;
105
121
 
106
122
  const block = moduleGraph.getParentBlock(d);
107
123
  let index = moduleGraph.getParentBlockIndex(d);
@@ -115,41 +131,47 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
115
131
  modules = blockModulesMap.get((blockCache = block));
116
132
  }
117
133
 
118
- const i = index << 2;
134
+ const i = index * 3;
119
135
  modules[i] = m;
120
- modules[i + 1] = state;
136
+ modules[i + 1] = connection.getActiveState(runtime);
137
+ modules[i + 2] = connection;
121
138
  }
122
139
 
123
140
  for (const modules of arrays) {
124
141
  if (modules.length === 0) continue;
125
142
  let indexMap;
126
143
  let length = 0;
127
- outer: for (let j = 0; j < modules.length; j += 2) {
144
+ outer: for (let j = 0; j < modules.length; j += 3) {
128
145
  const m = modules[j];
129
146
  if (m === undefined) continue;
130
147
  const state = modules[j + 1];
148
+ const connection = modules[j + 2];
131
149
  if (indexMap === undefined) {
132
150
  let i = 0;
133
- for (; i < length; i += 2) {
151
+ for (; i < length; i += 3) {
134
152
  if (modules[i] === m) {
135
153
  const merged = modules[i + 1];
154
+ modules[i + 2].push(connection);
136
155
  if (merged === true) continue outer;
137
156
  modules[i + 1] = ModuleGraphConnection.addConnectionStates(
138
157
  merged,
139
158
  state
140
159
  );
160
+ continue outer;
141
161
  }
142
162
  }
143
163
  modules[length] = m;
144
164
  length++;
145
165
  modules[length] = state;
146
166
  length++;
167
+ modules[length] = [connection];
168
+ length++;
147
169
  if (length > 30) {
148
170
  // To avoid worse case performance, we will use an index map for
149
171
  // linear cost access, which allows to maintain O(n) complexity
150
172
  // while keeping allocations down to a minimum
151
173
  indexMap = new Map();
152
- for (let i = 0; i < length; i += 2) {
174
+ for (let i = 0; i < length; i += 3) {
153
175
  indexMap.set(modules[i], i + 1);
154
176
  }
155
177
  }
@@ -157,6 +179,7 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
157
179
  const idx = indexMap.get(m);
158
180
  if (idx !== undefined) {
159
181
  const merged = modules[idx];
182
+ modules[idx + 1].push(connection);
160
183
  if (merged === true) continue outer;
161
184
  modules[idx] = ModuleGraphConnection.addConnectionStates(
162
185
  merged,
@@ -168,6 +191,8 @@ const extractBlockModules = (module, moduleGraph, runtime, blockModulesMap) => {
168
191
  modules[length] = state;
169
192
  indexMap.set(m, length);
170
193
  length++;
194
+ modules[length] = [connection];
195
+ length++;
171
196
  }
172
197
  }
173
198
  }
@@ -207,7 +232,7 @@ const visitModules = (
207
232
  *
208
233
  * @param {DependenciesBlock} block block
209
234
  * @param {RuntimeSpec} runtime runtime
210
- * @returns {(Module | ConnectionState)[]} block modules in flatten tuples
235
+ * @returns {(Module | ConnectionState | ModuleGraphConnection[])[]} block modules in flatten tuples
211
236
  */
212
237
  const getBlockModules = (block, runtime) => {
213
238
  if (blockModulesMapRuntime !== runtime) {
@@ -266,12 +291,18 @@ const visitModules = (
266
291
  /** @type {Map<DependenciesBlock, ChunkGroupInfo>} */
267
292
  const blockChunkGroups = new Map();
268
293
 
294
+ /** @type {Map<ChunkGroupInfo, DependenciesBlock>} */
295
+ const blockByChunkGroups = new Map();
296
+
269
297
  /** @type {Map<string, ChunkGroupInfo>} */
270
298
  const namedChunkGroups = new Map();
271
299
 
272
300
  /** @type {Map<string, ChunkGroupInfo>} */
273
301
  const namedAsyncEntrypoints = new Map();
274
302
 
303
+ /** @type {Set<ChunkGroupInfo>} */
304
+ const outdatedOrderIndexChunkGroups = new Set();
305
+
275
306
  const ADD_AND_ENTER_ENTRY_MODULE = 0;
276
307
  const ADD_AND_ENTER_MODULE = 1;
277
308
  const ENTER_MODULE = 2;
@@ -376,7 +407,7 @@ const visitModules = (
376
407
  /** @type {QueueItem[]} */
377
408
  let queueDelayed = [];
378
409
 
379
- /** @type {[Module, ConnectionState][]} */
410
+ /** @type {[Module, ModuleGraphConnection[]][]} */
380
411
  const skipConnectionBuffer = [];
381
412
  /** @type {Module[]} */
382
413
  const skipBuffer = [];
@@ -524,6 +555,7 @@ const visitModules = (
524
555
  blockConnections.set(b, []);
525
556
  }
526
557
  blockChunkGroups.set(b, /** @type {ChunkGroupInfo} */ (cgi));
558
+ blockByChunkGroups.set(cgi, b);
527
559
  } else if (entryOptions) {
528
560
  entrypoint = /** @type {Entrypoint} */ (cgi.chunkGroup);
529
561
  } else {
@@ -575,7 +607,7 @@ const visitModules = (
575
607
  const { minAvailableModules } = chunkGroupInfo;
576
608
  // Buffer items because order need to be reversed to get indices correct
577
609
  // Traverse all referenced modules
578
- for (let i = 0; i < blockModules.length; i += 2) {
610
+ for (let i = 0; i < blockModules.length; i += 3) {
579
611
  const refModule = /** @type {Module} */ (blockModules[i]);
580
612
  if (chunkGraph.isModuleInChunk(refModule, chunk)) {
581
613
  // skip early if already connected
@@ -585,7 +617,11 @@ const visitModules = (
585
617
  blockModules[i + 1]
586
618
  );
587
619
  if (activeState !== true) {
588
- skipConnectionBuffer.push([refModule, activeState]);
620
+ const connections = /** @type {ModuleGraphConnection[]} */ (
621
+ blockModules[i + 2]
622
+ );
623
+ skipConnectionBuffer.push([refModule, connections]);
624
+ // We skip inactive connections
589
625
  if (activeState === false) continue;
590
626
  }
591
627
  if (
@@ -659,7 +695,7 @@ const visitModules = (
659
695
 
660
696
  if (blockModules !== undefined) {
661
697
  // Traverse all referenced modules
662
- for (let i = 0; i < blockModules.length; i += 2) {
698
+ for (let i = 0; i < blockModules.length; i += 3) {
663
699
  const refModule = /** @type {Module} */ (blockModules[i]);
664
700
  const activeState = /** @type {ConnectionState} */ (
665
701
  blockModules[i + 1]
@@ -1165,7 +1201,11 @@ const visitModules = (
1165
1201
  /** @type {ModuleSetPlus} */
1166
1202
  (info.minAvailableModules);
1167
1203
  for (const entry of info.skippedModuleConnections) {
1168
- const [module, activeState] = entry;
1204
+ const [module, connections] = entry;
1205
+ const activeState = getActiveStateOfConnections(
1206
+ connections,
1207
+ info.runtime
1208
+ );
1169
1209
  if (activeState === false) continue;
1170
1210
  if (activeState === true) {
1171
1211
  info.skippedModuleConnections.delete(entry);
@@ -1208,6 +1248,7 @@ const visitModules = (
1208
1248
  chunkGroupsForCombining.add(cgi);
1209
1249
  }
1210
1250
  }
1251
+ outdatedOrderIndexChunkGroups.add(info);
1211
1252
  }
1212
1253
  outdatedChunkGroupInfo.clear();
1213
1254
  };
@@ -1254,6 +1295,51 @@ const visitModules = (
1254
1295
  }
1255
1296
  }
1256
1297
 
1298
+ for (const info of outdatedOrderIndexChunkGroups) {
1299
+ const { chunkGroup, runtime } = info;
1300
+
1301
+ const block = blockByChunkGroups.get(info);
1302
+
1303
+ if (!block) {
1304
+ continue;
1305
+ }
1306
+
1307
+ let preOrderIndex = 0;
1308
+ let postOrderIndex = 0;
1309
+
1310
+ const process = (current, visited = new Set()) => {
1311
+ if (visited.has(current)) {
1312
+ return;
1313
+ }
1314
+
1315
+ visited.add(current);
1316
+
1317
+ const blockModules = getBlockModules(current, runtime);
1318
+ if (blockModules === undefined) {
1319
+ return;
1320
+ }
1321
+
1322
+ for (let i = 0; i < blockModules.length; i += 3) {
1323
+ const refModule = /** @type {Module} */ (blockModules[i]);
1324
+ const activeState = /** @type {ConnectionState} */ (
1325
+ blockModules[i + 1]
1326
+ );
1327
+ if (activeState === false) {
1328
+ continue;
1329
+ }
1330
+
1331
+ if (refModule) {
1332
+ chunkGroup.setModulePreOrderIndex(refModule, preOrderIndex++);
1333
+ process(refModule, visited);
1334
+ chunkGroup.setModulePostOrderIndex(refModule, postOrderIndex++);
1335
+ }
1336
+ }
1337
+ };
1338
+
1339
+ process(block);
1340
+ }
1341
+ outdatedOrderIndexChunkGroups.clear();
1342
+
1257
1343
  logger.log(
1258
1344
  `${statProcessedQueueItems} queue items processed (${statProcessedBlocks} blocks)`
1259
1345
  );