@depup/webpack 5.109.0-depup.0 → 5.109.2-depup.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 (62) hide show
  1. package/README.md +4 -4
  2. package/bin/webpack.js +12 -0
  3. package/changes.json +4 -4
  4. package/lib/ChunkGraph.js +17 -15
  5. package/lib/CleanPlugin.js +11 -9
  6. package/lib/CompatibilityPlugin.js +31 -0
  7. package/lib/Compilation.js +21 -5
  8. package/lib/Compiler.js +16 -4
  9. package/lib/DefinePlugin.js +47 -20
  10. package/lib/ExportsInfo.js +22 -5
  11. package/lib/ExternalModule.js +10 -7
  12. package/lib/FileSystemInfo.js +126 -26
  13. package/lib/FlagDependencyUsagePlugin.js +33 -12
  14. package/lib/InitFragment.js +20 -32
  15. package/lib/ModuleFilenameHelpers.js +13 -2
  16. package/lib/NormalModule.js +80 -71
  17. package/lib/NormalModuleFactory.js +8 -2
  18. package/lib/RuntimePlugin.js +40 -113
  19. package/lib/Template.js +23 -3
  20. package/lib/cache/PackFileCacheStrategy.js +259 -5
  21. package/lib/config/defaults.js +21 -2
  22. package/lib/container/HoistContainerReferencesPlugin.js +47 -55
  23. package/lib/container/ModuleFederationPlugin.js +15 -9
  24. package/lib/css/CssGenerator.js +8 -2
  25. package/lib/css/CssLoadingRuntimeModule.js +25 -12
  26. package/lib/css/CssModulesPlugin.js +29 -18
  27. package/lib/css/CssParser.js +135 -50
  28. package/lib/css/syntax.js +862 -765
  29. package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
  30. package/lib/dependencies/CommonJsFullRequireDependency.js +33 -4
  31. package/lib/dependencies/CommonJsImportsParserPlugin.js +2 -0
  32. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
  33. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
  34. package/lib/dependencies/HarmonyImportDependency.js +1 -1
  35. package/lib/dependencies/HarmonyImportGuard.js +2 -1
  36. package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
  37. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +15 -9
  38. package/lib/hmr/lazyCompilationBackend.js +19 -4
  39. package/lib/html/HtmlGenerator.js +23 -3
  40. package/lib/html/HtmlModulesPlugin.js +30 -12
  41. package/lib/html/syntax.js +2485 -2399
  42. package/lib/ids/IdHelpers.js +24 -10
  43. package/lib/javascript/JavascriptModulesPlugin.js +83 -49
  44. package/lib/javascript/JavascriptParser.js +49 -13
  45. package/lib/javascript/syntax.js +700 -43
  46. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +10 -2
  47. package/lib/node/ReadFileCompileWasmPlugin.js +10 -2
  48. package/lib/optimize/AggressiveMergingPlugin.js +19 -15
  49. package/lib/optimize/ConcatenatedModule.js +19 -15
  50. package/lib/optimize/ModuleConcatenationPlugin.js +73 -24
  51. package/lib/optimize/RealContentHashPlugin.js +10 -7
  52. package/lib/optimize/SplitChunksPlugin.js +146 -44
  53. package/lib/prefetch/ResourceHintPlugin.js +96 -72
  54. package/lib/serialization/BinaryMiddleware.js +270 -938
  55. package/lib/serialization/FileMiddleware.js +299 -60
  56. package/lib/stats/DefaultStatsFactoryPlugin.js +204 -198
  57. package/lib/stats/DefaultStatsPrinterPlugin.js +24 -166
  58. package/lib/stats/StatsFactory.js +31 -9
  59. package/lib/util/identifier.js +21 -1
  60. package/package.json +10 -10
  61. package/schemas/WebpackOptions.json +110 -55
  62. package/types.d.ts +832 -247
@@ -297,6 +297,22 @@ class SnapshotIterable {
297
297
  /** @typedef {Set<string>} ManagedMissing */
298
298
  /** @typedef {Set<Snapshot>} Children */
299
299
 
300
+ // `Snapshot._flags` bit for each optional field. Serialized as a whole integer,
301
+ // so these values are a persisted-cache format contract — never renumber them.
302
+ const SNAPSHOT_FLAG_START_TIME = 1;
303
+ const SNAPSHOT_FLAG_FILE_TIMESTAMPS = 2;
304
+ const SNAPSHOT_FLAG_FILE_HASHES = 4;
305
+ const SNAPSHOT_FLAG_FILE_TSHS = 8;
306
+ const SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS = 0x10;
307
+ const SNAPSHOT_FLAG_CONTEXT_HASHES = 0x20;
308
+ const SNAPSHOT_FLAG_CONTEXT_TSHS = 0x40;
309
+ const SNAPSHOT_FLAG_MISSING_EXISTENCE = 0x80;
310
+ const SNAPSHOT_FLAG_MANAGED_ITEM_INFO = 0x100;
311
+ const SNAPSHOT_FLAG_MANAGED_FILES = 0x200;
312
+ const SNAPSHOT_FLAG_MANAGED_CONTEXTS = 0x400;
313
+ const SNAPSHOT_FLAG_MANAGED_MISSING = 0x800;
314
+ const SNAPSHOT_FLAG_CHILDREN = 0x1000;
315
+
300
316
  class Snapshot {
301
317
  constructor() {
302
318
  /** @type {number} */
@@ -336,7 +352,7 @@ class Snapshot {
336
352
  }
337
353
 
338
354
  hasStartTime() {
339
- return (this._flags & 1) !== 0;
355
+ return (this._flags & SNAPSHOT_FLAG_START_TIME) !== 0;
340
356
  }
341
357
 
342
358
  /**
@@ -344,7 +360,7 @@ class Snapshot {
344
360
  * @param {number} value start value
345
361
  */
346
362
  setStartTime(value) {
347
- this._flags |= 1;
363
+ this._flags |= SNAPSHOT_FLAG_START_TIME;
348
364
  this.startTime = value;
349
365
  }
350
366
 
@@ -375,7 +391,7 @@ class Snapshot {
375
391
  }
376
392
 
377
393
  hasFileTimestamps() {
378
- return (this._flags & 2) !== 0;
394
+ return (this._flags & SNAPSHOT_FLAG_FILE_TIMESTAMPS) !== 0;
379
395
  }
380
396
 
381
397
  /**
@@ -383,12 +399,12 @@ class Snapshot {
383
399
  * @param {FileTimestamps} value file timestamps
384
400
  */
385
401
  setFileTimestamps(value) {
386
- this._flags |= 2;
402
+ this._flags |= SNAPSHOT_FLAG_FILE_TIMESTAMPS;
387
403
  this.fileTimestamps = value;
388
404
  }
389
405
 
390
406
  hasFileHashes() {
391
- return (this._flags & 4) !== 0;
407
+ return (this._flags & SNAPSHOT_FLAG_FILE_HASHES) !== 0;
392
408
  }
393
409
 
394
410
  /**
@@ -396,12 +412,12 @@ class Snapshot {
396
412
  * @param {FileHashes} value file hashes
397
413
  */
398
414
  setFileHashes(value) {
399
- this._flags |= 4;
415
+ this._flags |= SNAPSHOT_FLAG_FILE_HASHES;
400
416
  this.fileHashes = value;
401
417
  }
402
418
 
403
419
  hasFileTshs() {
404
- return (this._flags & 8) !== 0;
420
+ return (this._flags & SNAPSHOT_FLAG_FILE_TSHS) !== 0;
405
421
  }
406
422
 
407
423
  /**
@@ -409,12 +425,12 @@ class Snapshot {
409
425
  * @param {FileTshs} value file tshs
410
426
  */
411
427
  setFileTshs(value) {
412
- this._flags |= 8;
428
+ this._flags |= SNAPSHOT_FLAG_FILE_TSHS;
413
429
  this.fileTshs = value;
414
430
  }
415
431
 
416
432
  hasContextTimestamps() {
417
- return (this._flags & 0x10) !== 0;
433
+ return (this._flags & SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS) !== 0;
418
434
  }
419
435
 
420
436
  /**
@@ -422,12 +438,12 @@ class Snapshot {
422
438
  * @param {ContextTimestamps} value context timestamps
423
439
  */
424
440
  setContextTimestamps(value) {
425
- this._flags |= 0x10;
441
+ this._flags |= SNAPSHOT_FLAG_CONTEXT_TIMESTAMPS;
426
442
  this.contextTimestamps = value;
427
443
  }
428
444
 
429
445
  hasContextHashes() {
430
- return (this._flags & 0x20) !== 0;
446
+ return (this._flags & SNAPSHOT_FLAG_CONTEXT_HASHES) !== 0;
431
447
  }
432
448
 
433
449
  /**
@@ -435,12 +451,12 @@ class Snapshot {
435
451
  * @param {ContextHashes} value context hashes
436
452
  */
437
453
  setContextHashes(value) {
438
- this._flags |= 0x20;
454
+ this._flags |= SNAPSHOT_FLAG_CONTEXT_HASHES;
439
455
  this.contextHashes = value;
440
456
  }
441
457
 
442
458
  hasContextTshs() {
443
- return (this._flags & 0x40) !== 0;
459
+ return (this._flags & SNAPSHOT_FLAG_CONTEXT_TSHS) !== 0;
444
460
  }
445
461
 
446
462
  /**
@@ -448,12 +464,12 @@ class Snapshot {
448
464
  * @param {ContextTshs} value context tshs
449
465
  */
450
466
  setContextTshs(value) {
451
- this._flags |= 0x40;
467
+ this._flags |= SNAPSHOT_FLAG_CONTEXT_TSHS;
452
468
  this.contextTshs = value;
453
469
  }
454
470
 
455
471
  hasMissingExistence() {
456
- return (this._flags & 0x80) !== 0;
472
+ return (this._flags & SNAPSHOT_FLAG_MISSING_EXISTENCE) !== 0;
457
473
  }
458
474
 
459
475
  /**
@@ -461,12 +477,12 @@ class Snapshot {
461
477
  * @param {MissingExistence} value context tshs
462
478
  */
463
479
  setMissingExistence(value) {
464
- this._flags |= 0x80;
480
+ this._flags |= SNAPSHOT_FLAG_MISSING_EXISTENCE;
465
481
  this.missingExistence = value;
466
482
  }
467
483
 
468
484
  hasManagedItemInfo() {
469
- return (this._flags & 0x100) !== 0;
485
+ return (this._flags & SNAPSHOT_FLAG_MANAGED_ITEM_INFO) !== 0;
470
486
  }
471
487
 
472
488
  /**
@@ -474,12 +490,12 @@ class Snapshot {
474
490
  * @param {ManagedItemInfo} value managed item info
475
491
  */
476
492
  setManagedItemInfo(value) {
477
- this._flags |= 0x100;
493
+ this._flags |= SNAPSHOT_FLAG_MANAGED_ITEM_INFO;
478
494
  this.managedItemInfo = value;
479
495
  }
480
496
 
481
497
  hasManagedFiles() {
482
- return (this._flags & 0x200) !== 0;
498
+ return (this._flags & SNAPSHOT_FLAG_MANAGED_FILES) !== 0;
483
499
  }
484
500
 
485
501
  /**
@@ -487,12 +503,12 @@ class Snapshot {
487
503
  * @param {ManagedFiles} value managed files
488
504
  */
489
505
  setManagedFiles(value) {
490
- this._flags |= 0x200;
506
+ this._flags |= SNAPSHOT_FLAG_MANAGED_FILES;
491
507
  this.managedFiles = value;
492
508
  }
493
509
 
494
510
  hasManagedContexts() {
495
- return (this._flags & 0x400) !== 0;
511
+ return (this._flags & SNAPSHOT_FLAG_MANAGED_CONTEXTS) !== 0;
496
512
  }
497
513
 
498
514
  /**
@@ -500,12 +516,12 @@ class Snapshot {
500
516
  * @param {ManagedContexts} value managed contexts
501
517
  */
502
518
  setManagedContexts(value) {
503
- this._flags |= 0x400;
519
+ this._flags |= SNAPSHOT_FLAG_MANAGED_CONTEXTS;
504
520
  this.managedContexts = value;
505
521
  }
506
522
 
507
523
  hasManagedMissing() {
508
- return (this._flags & 0x800) !== 0;
524
+ return (this._flags & SNAPSHOT_FLAG_MANAGED_MISSING) !== 0;
509
525
  }
510
526
 
511
527
  /**
@@ -513,12 +529,12 @@ class Snapshot {
513
529
  * @param {ManagedMissing} value managed missing
514
530
  */
515
531
  setManagedMissing(value) {
516
- this._flags |= 0x800;
532
+ this._flags |= SNAPSHOT_FLAG_MANAGED_MISSING;
517
533
  this.managedMissing = value;
518
534
  }
519
535
 
520
536
  hasChildren() {
521
- return (this._flags & 0x1000) !== 0;
537
+ return (this._flags & SNAPSHOT_FLAG_CHILDREN) !== 0;
522
538
  }
523
539
 
524
540
  /**
@@ -526,7 +542,7 @@ class Snapshot {
526
542
  * @param {Children} value children
527
543
  */
528
544
  setChildren(value) {
529
- this._flags |= 0x1000;
545
+ this._flags |= SNAPSHOT_FLAG_CHILDREN;
530
546
  this.children = value;
531
547
  }
532
548
 
@@ -1221,6 +1237,58 @@ const addAll = (source, target) => {
1221
1237
 
1222
1238
  const getEsModuleLexer = memoize(() => require("es-module-lexer"));
1223
1239
 
1240
+ const getAcorn = memoize(/* istanbul ignore next */ () => require("acorn"));
1241
+
1242
+ // Bun doesn't populate `require.cache` `module.children`, so the CJS build-dependency
1243
+ // walk needs a source-parsing fallback there. Node/Deno populate it — never pay for it.
1244
+ const IS_BUN = Boolean(process.versions.bun);
1245
+
1246
+ /**
1247
+ * Collects static `require("literal")` specifiers from CommonJS source. Used as a
1248
+ * fallback where `require.cache` children aren't populated (e.g. Bun), so build
1249
+ * dependencies of a CJS file are still tracked. Dynamic requires can't be seen here.
1250
+ * @param {string} source source
1251
+ * @returns {Set<string>} required specifiers
1252
+ */
1253
+ // Bun-only: exercised by BuildDependencies.longtest under the Bun CI job (no coverage upload).
1254
+ /* istanbul ignore next */
1255
+ const parseCjsRequires = (source) => {
1256
+ /** @type {Set<string>} */
1257
+ const requires = new Set();
1258
+ const ast = getAcorn().parse(source, {
1259
+ ecmaVersion: "latest",
1260
+ sourceType: "script",
1261
+ allowReturnOutsideFunction: true
1262
+ });
1263
+ /** @type {EXPECTED_ANY[]} */
1264
+ const stack = [ast];
1265
+ while (stack.length > 0) {
1266
+ const node = stack.pop();
1267
+ if (!node || typeof node.type !== "string") continue;
1268
+ if (
1269
+ node.type === "CallExpression" &&
1270
+ node.callee.type === "Identifier" &&
1271
+ node.callee.name === "require" &&
1272
+ node.arguments.length === 1 &&
1273
+ node.arguments[0].type === "Literal" &&
1274
+ typeof node.arguments[0].value === "string"
1275
+ ) {
1276
+ requires.add(node.arguments[0].value);
1277
+ }
1278
+ for (const key of Object.keys(node)) {
1279
+ const value = node[key];
1280
+ if (Array.isArray(value)) {
1281
+ for (const item of value) {
1282
+ if (item && typeof item.type === "string") stack.push(item);
1283
+ }
1284
+ } else if (value && typeof value.type === "string") {
1285
+ stack.push(value);
1286
+ }
1287
+ }
1288
+ }
1289
+ return requires;
1290
+ };
1291
+
1224
1292
  /** @typedef {Set<string>} LoggedPaths */
1225
1293
 
1226
1294
  /** @typedef {FileSystemInfoEntry | ExistenceOnlyTimeEntry | "ignore" | null} FileTimestamp */
@@ -2213,6 +2281,38 @@ class FileSystemInfo {
2213
2281
  });
2214
2282
  }
2215
2283
  }
2284
+ // On Bun the children array is empty (unpopulated), so recover the
2285
+ // static require() specifiers by parsing the source; Node/Deno don't.
2286
+ /* istanbul ignore next */
2287
+ if (IS_BUN && module.children.length === 0) {
2288
+ this.fs.readFile(path, (err, content) => {
2289
+ if (err) return callback(err);
2290
+ try {
2291
+ const context = dirname(this.fs, path);
2292
+ const source = /** @type {Buffer} */ (content).toString();
2293
+ /** @type {Set<string>} */
2294
+ const added = new Set();
2295
+ for (const dependency of parseCjsRequires(source)) {
2296
+ if (dependency.startsWith("node:")) continue;
2297
+ if (builtinModules.has(dependency)) continue;
2298
+ if (added.has(dependency)) continue;
2299
+ push({
2300
+ type: RBDT_RESOLVE_CJS_FILE,
2301
+ context,
2302
+ path: dependency,
2303
+ // Best effort: tolerate specifiers that don't resolve.
2304
+ expected: false,
2305
+ issuer: job
2306
+ });
2307
+ added.add(dependency);
2308
+ }
2309
+ } catch (_err) {
2310
+ // Source we can't parse as CommonJS — ignore its dependencies.
2311
+ }
2312
+ process.nextTick(callback);
2313
+ });
2314
+ break;
2315
+ }
2216
2316
  } else if (supportsEsm && /\.m?js$/.test(path)) {
2217
2317
  if (!this._warnAboutExperimentalEsmTracking) {
2218
2318
  logger.log(
@@ -30,6 +30,19 @@ const {
30
30
  const PLUGIN_NAME = "FlagDependencyUsagePlugin";
31
31
  const PLUGIN_LOGGER_NAME = `webpack.${PLUGIN_NAME}`;
32
32
 
33
+ // Hoisted stateless predicates for setUsedConditionally on the innermost
34
+ // used-export loop, so they aren't re-allocated per export.
35
+ /**
36
+ * @param {import("./ExportsInfo").UsageStateType} used usage state
37
+ * @returns {boolean} whether unused
38
+ */
39
+ const IS_UNUSED = (used) => used === UsageState.Unused;
40
+ /**
41
+ * @param {import("./ExportsInfo").UsageStateType} used usage state
42
+ * @returns {boolean} whether not used
43
+ */
44
+ const IS_NOT_USED = (used) => used !== UsageState.Used;
45
+
33
46
  class FlagDependencyUsagePlugin {
34
47
  /**
35
48
  * Creates an instance of FlagDependencyUsagePlugin.
@@ -162,7 +175,7 @@ class FlagDependencyUsagePlugin {
162
175
  if (nestedInfo) {
163
176
  if (
164
177
  exportInfo.setUsedConditionally(
165
- (used) => used === UsageState.Unused,
178
+ IS_UNUSED,
166
179
  UsageState.OnlyPropertiesUsed,
167
180
  runtime
168
181
  )
@@ -181,7 +194,7 @@ class FlagDependencyUsagePlugin {
181
194
  }
182
195
  if (
183
196
  exportInfo.setUsedConditionally(
184
- (v) => v !== UsageState.Used,
197
+ IS_NOT_USED,
185
198
  UsageState.Used,
186
199
  runtime
187
200
  )
@@ -229,8 +242,9 @@ class FlagDependencyUsagePlugin {
229
242
  // Modules whose whole namespace object escapes in a mangleable way.
230
243
  // Tracked separately so specific member references are still merged
231
244
  // (and marked used) instead of being dropped by the escape marker.
232
- /** @type {Set<Module>} */
233
- const mangleableEscapeModules = new Set();
245
+ // Lazily allocated — usually empty.
246
+ /** @type {Set<Module> | undefined} */
247
+ let mangleableEscapeModules;
234
248
 
235
249
  /** @type {ArrayQueue<DependenciesBlock>} */
236
250
  const queue = new ArrayQueue();
@@ -273,7 +287,9 @@ class FlagDependencyUsagePlugin {
273
287
  // conservative result and always wins.
274
288
  if (referencedExports === EXPORTS_OBJECT_REFERENCED) {
275
289
  map.set(module, EXPORTS_OBJECT_REFERENCED);
276
- mangleableEscapeModules.delete(module);
290
+ if (mangleableEscapeModules) {
291
+ mangleableEscapeModules.delete(module);
292
+ }
277
293
  continue;
278
294
  }
279
295
  // A mangleable whole-object escape keeps the module's exports
@@ -284,6 +300,9 @@ class FlagDependencyUsagePlugin {
284
300
  if (
285
301
  referencedExports === EXPORTS_OBJECT_REFERENCED_MANGLEABLE
286
302
  ) {
303
+ if (mangleableEscapeModules === undefined) {
304
+ mangleableEscapeModules = new Set();
305
+ }
287
306
  mangleableEscapeModules.add(module);
288
307
  continue;
289
308
  }
@@ -358,13 +377,15 @@ class FlagDependencyUsagePlugin {
358
377
  );
359
378
  }
360
379
  }
361
- for (const module of mangleableEscapeModules) {
362
- processReferencedModule(
363
- module,
364
- EXPORTS_OBJECT_REFERENCED_MANGLEABLE,
365
- runtime,
366
- forceSideEffects
367
- );
380
+ if (mangleableEscapeModules) {
381
+ for (const module of mangleableEscapeModules) {
382
+ processReferencedModule(
383
+ module,
384
+ EXPORTS_OBJECT_REFERENCED_MANGLEABLE,
385
+ runtime,
386
+ forceSideEffects
387
+ );
388
+ }
368
389
  }
369
390
  };
370
391
 
@@ -28,30 +28,6 @@ const makeSerializable = require("./util/makeSerializable");
28
28
  * @property {(fragments: MaybeMergeableInitFragment<GenerateContext>[]) => MaybeMergeableInitFragment<GenerateContext>[]=} mergeAll
29
29
  */
30
30
 
31
- /**
32
- * Extract fragment index.
33
- * @template T
34
- * @param {T} fragment the init fragment
35
- * @param {number} index index
36
- * @returns {[T, number]} tuple with both
37
- */
38
- const extractFragmentIndex = (fragment, index) => [fragment, index];
39
-
40
- /**
41
- * Sorts fragment with index.
42
- * @template T
43
- * @param {[MaybeMergeableInitFragment<T>, number]} a first pair
44
- * @param {[MaybeMergeableInitFragment<T>, number]} b second pair
45
- * @returns {number} sort value
46
- */
47
- const sortFragmentWithIndex = ([a, i], [b, j]) => {
48
- const stageCmp = a.stage - b.stage;
49
- if (stageCmp !== 0) return stageCmp;
50
- const positionCmp = a.position - b.position;
51
- if (positionCmp !== 0) return positionCmp;
52
- return i - j;
53
- };
54
-
55
31
  /**
56
32
  * Represents InitFragment.
57
33
  * @template GenerateContext
@@ -107,16 +83,28 @@ class InitFragment {
107
83
  */
108
84
  static addToSource(source, initFragments, context) {
109
85
  if (initFragments.length > 0) {
110
- // Sort fragments by position. If 2 fragments have the same position,
111
- // use their index.
112
- const sortedFragments = initFragments
113
- .map(extractFragmentIndex)
114
- .sort(sortFragmentWithIndex);
86
+ // Sort fragment indices by (stage, position), falling back to the
87
+ // original index — one flat number array instead of N [fragment, index]
88
+ // tuples for a stable-by-index order.
89
+ const sortedIndices = initFragments.map((_, index) => index);
90
+ sortedIndices.sort((a, b) => {
91
+ const fragmentA = initFragments[a];
92
+ const fragmentB = initFragments[b];
93
+ const stageCmp = fragmentA.stage - fragmentB.stage;
94
+ if (stageCmp !== 0) return stageCmp;
95
+ const positionCmp = fragmentA.position - fragmentB.position;
96
+ if (positionCmp !== 0) return positionCmp;
97
+ return a - b;
98
+ });
115
99
 
116
100
  // Deduplicate fragments. If a fragment has no key, it is always included.
117
- /** @type {Map<InitFragmentKey | symbol, MaybeMergeableInitFragment<Context> | MaybeMergeableInitFragment<Context>[]>} */
101
+ // Keyless fragments get a unique numeric key; number keys never collide
102
+ // with the string `InitFragmentKey`s used for keyed fragments.
103
+ /** @type {Map<InitFragmentKey | number, MaybeMergeableInitFragment<Context> | MaybeMergeableInitFragment<Context>[]>} */
118
104
  const keyedFragments = new Map();
119
- for (const [fragment] of sortedFragments) {
105
+ let keylessKey = 0;
106
+ for (const index of sortedIndices) {
107
+ const fragment = initFragments[index];
120
108
  if (typeof fragment.mergeAll === "function") {
121
109
  if (!fragment.key) {
122
110
  throw new Error(
@@ -142,7 +130,7 @@ class InitFragment {
142
130
  continue;
143
131
  }
144
132
  }
145
- keyedFragments.set(fragment.key || Symbol("fragment key"), fragment);
133
+ keyedFragments.set(fragment.key || keylessKey++, fragment);
146
134
  }
147
135
 
148
136
  const concatSource = new ConcatSource();
@@ -169,11 +169,14 @@ ModuleFilenameHelpers.createFilename = (
169
169
  let moduleId;
170
170
  /** @type {ReturnStringCallback} */
171
171
  let shortIdentifier;
172
+ /** @type {ReturnStringCallback} */
173
+ let resourceIdentifier;
172
174
  if (typeof module === "string") {
173
175
  shortIdentifier =
174
176
  /** @type {ReturnStringCallback} */
175
177
  (memoize(() => requestShortener.shorten(module)));
176
178
  identifier = shortIdentifier;
179
+ resourceIdentifier = shortIdentifier;
177
180
  moduleId = () => "";
178
181
  absoluteResourcePath = () =>
179
182
  /** @type {string} */ (module.split("!").pop());
@@ -182,6 +185,14 @@ ModuleFilenameHelpers.createFilename = (
182
185
  shortIdentifier = memoize(() =>
183
186
  module.readableIdentifier(requestShortener)
184
187
  );
188
+ // `[resource]` and `[loaders]` must stay request paths: a subclass's
189
+ // readable identifier may carry display-only decorations (e.g. CssModule's
190
+ // `css ` prefix)
191
+ resourceIdentifier = memoize(() =>
192
+ module instanceof NormalModule
193
+ ? /** @type {string} */ (requestShortener.shorten(module.userRequest))
194
+ : module.readableIdentifier(requestShortener)
195
+ );
185
196
  identifier =
186
197
  /** @type {ReturnStringCallback} */
187
198
  (memoize(() => requestShortener.shorten(module.identifier())));
@@ -196,9 +207,9 @@ ModuleFilenameHelpers.createFilename = (
196
207
  }
197
208
  const resource =
198
209
  /** @type {ReturnStringCallback} */
199
- (memoize(() => shortIdentifier().split("!").pop()));
210
+ (memoize(() => resourceIdentifier().split("!").pop()));
200
211
 
201
- const loaders = getBefore(shortIdentifier, "!");
212
+ const loaders = getBefore(resourceIdentifier, "!");
202
213
  const allLoaders = getBefore(identifier, "!");
203
214
  const query = getAfter(resource, "?");
204
215
  const resourcePath = () => {