webpack 5.111.0 → 5.111.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/lib/APIPlugin.js +3 -4
  2. package/lib/CompatibilityPlugin.js +3 -4
  3. package/lib/Compilation.js +16 -35
  4. package/lib/Compiler.js +4 -5
  5. package/lib/ConstPlugin.js +16 -132
  6. package/lib/DependencyTemplate.js +2 -1
  7. package/lib/DotenvPlugin.js +24 -28
  8. package/lib/ErrorHelpers.js +113 -0
  9. package/lib/ExportsInfo.js +20 -16
  10. package/lib/ExternalModule.js +6 -8
  11. package/lib/FlagDependencyExportsPlugin.js +8 -13
  12. package/lib/FlagDependencyUsagePlugin.js +9 -13
  13. package/lib/Generator.js +24 -2
  14. package/lib/HotModuleReplacementPlugin.js +2 -0
  15. package/lib/IgnorePlugin.js +1 -1
  16. package/lib/LoaderOptionsPlugin.js +1 -1
  17. package/lib/Module.js +3 -3
  18. package/lib/ModuleGraph.js +6 -9
  19. package/lib/MultiCompiler.js +6 -16
  20. package/lib/NormalModule.js +96 -44
  21. package/lib/RuntimeTemplate.js +33 -43
  22. package/lib/SourceMapDevToolPlugin.js +53 -103
  23. package/lib/TemplatedPathPlugin.js +16 -59
  24. package/lib/asset/AssetBytesGenerator.js +7 -1
  25. package/lib/asset/AssetGenerator.js +25 -16
  26. package/lib/asset/AssetSourceGenerator.js +7 -1
  27. package/lib/buildChunkGraph.js +11 -15
  28. package/lib/cache/MemoryCachePlugin.js +4 -4
  29. package/lib/cache/MemoryWithGcCachePlugin.js +7 -8
  30. package/lib/cache/PackFileCacheStrategy.js +3 -18
  31. package/lib/cache/getLazyHashedEtag.js +3 -5
  32. package/lib/config/browserslistTargetHandler.js +2 -8
  33. package/lib/config/defaults.js +52 -78
  34. package/lib/config/getClaimedAssetTypes.js +10 -11
  35. package/lib/config/target.js +3 -4
  36. package/lib/{ContextExclusionPlugin.js → context/ContextExclusionPlugin.js} +1 -1
  37. package/lib/{ContextModule.js → context/ContextModule.js} +37 -34
  38. package/lib/{ContextModuleFactory.js → context/ContextModuleFactory.js} +19 -21
  39. package/lib/{ContextReplacementPlugin.js → context/ContextReplacementPlugin.js} +4 -4
  40. package/lib/css/CssGenerator.js +19 -11
  41. package/lib/css/CssParser.js +18 -20
  42. package/lib/css/cssMinify.js +32 -29
  43. package/lib/css/data.js +797 -288
  44. package/lib/css/syntax.js +2250 -934
  45. package/lib/debug/ProfilingPlugin.js +3 -4
  46. package/lib/dependencies/CommonJsExportRequireDependency.js +10 -11
  47. package/lib/dependencies/CommonJsImportsParserPlugin.js +4 -5
  48. package/lib/dependencies/CommonJsSelfReferenceDependency.js +2 -4
  49. package/lib/dependencies/ContextDependency.js +1 -1
  50. package/lib/dependencies/ContextDependencyHelpers.js +3 -9
  51. package/lib/dependencies/ContextElementDependency.js +1 -1
  52. package/lib/dependencies/CssIcssExportDependency.js +6 -8
  53. package/lib/dependencies/CssIcssImportDependency.js +3 -6
  54. package/lib/dependencies/CssUrlDependency.js +3 -5
  55. package/lib/dependencies/HarmonyCompatibilityDependency.js +11 -20
  56. package/lib/dependencies/HarmonyDetectionParserPlugin.js +3 -4
  57. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +2 -4
  58. package/lib/dependencies/HarmonyExportExpressionDependency.js +3 -4
  59. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +3 -4
  60. package/lib/dependencies/HarmonyExportInitFragment.js +26 -19
  61. package/lib/dependencies/HarmonyExportSpecifierDependency.js +7 -28
  62. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +103 -16
  63. package/lib/dependencies/HarmonyImportSideEffectDependency.js +3 -4
  64. package/lib/dependencies/HarmonyImportSpecifierDependency.js +16 -2
  65. package/lib/dependencies/HtmlEntryDependency.js +74 -102
  66. package/lib/dependencies/HtmlInlineScriptDependency.js +3 -4
  67. package/lib/dependencies/HtmlInlineStyleDependency.js +3 -4
  68. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  69. package/lib/dependencies/ImportMetaGlobHelpers.js +1 -1
  70. package/lib/dependencies/ImportMetaPlugin.js +8 -10
  71. package/lib/dependencies/ImportParserPlugin.js +1 -1
  72. package/lib/dependencies/LoaderPlugin.js +26 -1
  73. package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
  74. package/lib/dependencies/URLContextDependency.js +1 -1
  75. package/lib/dependencies/URLDependency.js +6 -5
  76. package/lib/dependencies/WorkerAndWorkletPlugin.js +15 -21
  77. package/lib/dependencies/WorkerDependency.js +6 -5
  78. package/lib/dependencies/WorkletDependency.js +6 -9
  79. package/lib/errors/HookWebpackError.js +3 -2
  80. package/lib/hmr/LazyCompilationPlugin.js +3 -5
  81. package/lib/html/HtmlGenerator.js +61 -82
  82. package/lib/html/HtmlModulesPlugin.js +88 -139
  83. package/lib/html/HtmlParser.js +97 -141
  84. package/lib/html/data.js +21 -0
  85. package/lib/html/htmlMinify.js +10 -11
  86. package/lib/html/syntax.js +883 -993
  87. package/lib/index.js +46 -3
  88. package/lib/javascript/ChunkFormatHelpers.js +4 -3
  89. package/lib/javascript/JavascriptGenerator.js +8 -1
  90. package/lib/javascript/JavascriptModulesPlugin.js +21 -48
  91. package/lib/javascript/JavascriptParser.js +721 -178
  92. package/lib/javascript/parser.js +6 -0
  93. package/lib/javascript/syntax.js +420 -92
  94. package/lib/json/JsonGenerator.js +7 -1
  95. package/lib/library/ModuleLibraryPlugin.js +64 -136
  96. package/lib/loaders/LoaderRunner.js +137 -9
  97. package/lib/node/NodeWatchFileSystem.js +3 -9
  98. package/lib/optimize/AggressiveMergingPlugin.js +3 -5
  99. package/lib/optimize/ConcatenatedModule.js +81 -100
  100. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -11
  101. package/lib/optimize/InnerGraphPlugin.js +7 -13
  102. package/lib/optimize/LimitChunkCountPlugin.js +5 -8
  103. package/lib/optimize/MangleExportsPlugin.js +3 -4
  104. package/lib/optimize/ModuleConcatenationPlugin.js +3 -4
  105. package/lib/optimize/SideEffectsFlagPlugin.js +7 -19
  106. package/lib/optimize/SplitChunksPlugin.js +2 -4
  107. package/lib/performance/BroadContextsPlugin.js +1 -1
  108. package/lib/performance/CacheEffectivenessPlugin.js +3 -4
  109. package/lib/performance/SizeLimitsPlugin.js +2 -4
  110. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +6 -8
  111. package/lib/prefetch/ResourceHintPlugin.js +17 -21
  112. package/lib/prefetch/StartupAssetHintRuntimeModule.js +7 -10
  113. package/lib/runtime/AsyncModuleRuntimeModule.js +3 -5
  114. package/lib/runtime/GetChunkFilenameRuntimeModule.js +3 -4
  115. package/lib/runtime/GlobalRuntimeModule.js +2 -4
  116. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +55 -85
  117. package/lib/schemes/DataUriPlugin.js +3 -6
  118. package/lib/schemes/VirtualUrlPlugin.js +1 -1
  119. package/lib/serialization/BinaryMiddleware.js +9 -9
  120. package/lib/serialization/FileMiddleware.js +16 -16
  121. package/lib/serialization/ObjectMiddleware.js +30 -33
  122. package/lib/stats/DefaultStatsFactoryPlugin.js +3 -4
  123. package/lib/typescript/TypeScriptPlugin.js +2 -3
  124. package/lib/url/URLParserPlugin.js +6 -8
  125. package/lib/util/LocConverter.js +4 -7
  126. package/lib/util/SourceProcessor.js +15 -22
  127. package/lib/util/chainedImports.js +3 -4
  128. package/lib/util/concatenate.js +4 -4
  129. package/lib/util/createHooksRegistry.js +1 -2
  130. package/lib/util/dataURL.js +2 -3
  131. package/lib/util/deterministicGrouping.js +8 -13
  132. package/lib/util/findGraphRoots.js +6 -13
  133. package/lib/util/globUtils.js +1 -1
  134. package/lib/util/hash/wasm-hash.js +3 -4
  135. package/lib/util/internalSerializables.js +1 -1
  136. package/lib/util/semver.js +5 -3
  137. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -1
  138. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -1
  139. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +3 -4
  140. package/lib/wasm-sync/WebAssemblyGenerator.js +6 -1
  141. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -1
  142. package/lib/wasm-sync/WebAssemblyUtils.js +2 -4
  143. package/package.json +30 -23
  144. package/types.d.ts +299 -280
@@ -36,7 +36,9 @@ const { ImportPhaseUtils, createGetImportPhase } = require("./ImportPhase");
36
36
  * Expression,
37
37
  * PrivateIdentifier,
38
38
  * Identifier,
39
- * MemberExpression
39
+ * MemberExpression,
40
+ * Pattern,
41
+ * UpdateExpression
40
42
  * } from "estree"
41
43
  */
42
44
  /**
@@ -50,7 +52,8 @@ const { ImportPhaseUtils, createGetImportPhase } = require("./ImportPhase");
50
52
  * @import JavascriptParser, {
51
53
  * ImportAttributes,
52
54
  * Range,
53
- * Members
55
+ * Members,
56
+ * WriteStatement
54
57
  * } from "../javascript/JavascriptParser"
55
58
  */
56
59
  /** @import { Ids, ExportPresenceMode } from "./HarmonyImportDependency" */
@@ -234,15 +237,18 @@ class HarmonyImportDependencyParserPlugin {
234
237
  this.options.sourceImport
235
238
  );
236
239
 
237
- // Parsers are reused across modules, so both are reset per program.
240
+ // Parsers are reused across modules, so all three are reset per program.
238
241
  /** @type {HarmonySettings[]} */
239
242
  const declaredSpecifiers = [];
240
243
  /** @type {HarmonyImportSideEffectDependency | undefined} */
241
244
  let lastSideEffectDependency;
245
+ /** @type {Identifier | MemberExpression | undefined} */
246
+ let assignmentTarget;
242
247
 
243
248
  parser.hooks.program.tap(PLUGIN_NAME, () => {
244
249
  declaredSpecifiers.length = 0;
245
250
  lastSideEffectDependency = undefined;
251
+ assignmentTarget = undefined;
246
252
  });
247
253
  parser.hooks.finish.tap(PLUGIN_NAME, () => {
248
254
  for (const settings of declaredSpecifiers) {
@@ -261,6 +267,7 @@ class HarmonyImportDependencyParserPlugin {
261
267
  }
262
268
  declaredSpecifiers.length = 0;
263
269
  lastSideEffectDependency = undefined;
270
+ assignmentTarget = undefined;
264
271
  });
265
272
 
266
273
  /**
@@ -399,14 +406,48 @@ class HarmonyImportDependencyParserPlugin {
399
406
  }
400
407
  }
401
408
  );
402
- // Concatenation would turn the binding into a plain local, losing the
403
- // getter-only property whose write throws.
404
- parser.hooks.assign.for(harmonySpecifierTag).tap(PLUGIN_NAME, (expr) => {
405
- const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
406
- markUsed(settings);
409
+ /**
410
+ * The reference a write lands on, which is a pattern for a
411
+ * destructuring write.
412
+ * @param {WriteStatement} node the construct performing the write
413
+ * @returns {Pattern | MemberExpression} the written reference
414
+ */
415
+ const writeTargetOf = (node) =>
416
+ /** @type {Pattern | MemberExpression} */ (
417
+ node.type === "UpdateExpression" ? node.argument : node.left
418
+ );
419
+
420
+ /**
421
+ * Whether a member write lands on the namespace object itself, which is
422
+ * read-only. A property of an imported object is an ordinary write.
423
+ * @param {HarmonySettings} settings the specifier's settings
424
+ * @param {Members} members the member chain
425
+ * @returns {boolean} true when the write targets a namespace member
426
+ */
427
+ const isNamespaceMemberWrite = (settings, members) =>
428
+ settings.ids.length === 0 && members.length === 1;
429
+
430
+ /**
431
+ * Keeps the module whole, for a write whose reference the output has no
432
+ * way to flag.
433
+ * @returns {void}
434
+ */
435
+ const bailOutOfConcatenation = () => {
407
436
  /** @type {JavascriptModuleBuildInfo} */
408
437
  (parser.state.module.buildInfo).moduleConcatenationBailout =
409
438
  "assignment to an imported binding";
439
+ };
440
+
441
+ /**
442
+ * Records the write target of an assignment or update to an imported
443
+ * binding, so the reference walked next renders as a throwing write.
444
+ * @param {WriteStatement} expr the write
445
+ * @param {Identifier | MemberExpression | undefined} target the written reference, if any
446
+ * @returns {void}
447
+ */
448
+ const markImportedBindingWrite = (expr, target) => {
449
+ const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
450
+ markUsed(settings);
410
451
  // A named import is written through the namespace's getter-only
411
452
  // property, which throws on its own. A namespace one is the binding
412
453
  // itself, and nothing webpack can emit for it throws, so report it.
@@ -414,8 +455,48 @@ class HarmonyImportDependencyParserPlugin {
414
455
  const error = new ImportedBindingAssignmentError(settings.name);
415
456
  error.loc = parser.getLocation(expr);
416
457
  parser.state.module.addError(error);
458
+ } else if (target) {
459
+ assignmentTarget = target;
460
+ } else {
461
+ // A destructuring target emits no reference to flag, so the whole
462
+ // module stays out of concatenation.
463
+ bailOutOfConcatenation();
417
464
  }
465
+ };
466
+
467
+ parser.hooks.assign.for(harmonySpecifierTag).tap(PLUGIN_NAME, (expr) => {
468
+ markImportedBindingWrite(
469
+ expr,
470
+ expr.left.type === "Identifier" ? expr.left : undefined
471
+ );
472
+ });
473
+ parser.hooks.write.for(harmonySpecifierTag).tap(PLUGIN_NAME, (node) => {
474
+ const written = writeTargetOf(node);
475
+ const target =
476
+ written.type === "Identifier"
477
+ ? /** @type {Identifier} */ (written)
478
+ : undefined;
479
+ markImportedBindingWrite(node, target);
480
+ // A loop's binding walks nothing on its own, so the reference the
481
+ // write renders as has to be walked here to exist at all.
482
+ if (!target || node.type === "UpdateExpression") return;
483
+ parser.walkExpression(target);
484
+ return true;
418
485
  });
486
+ // A namespace member is written through the reference its member chain
487
+ // emits, so both write forms flag that reference rather than the binding.
488
+ parser.hooks.writeMemberChain
489
+ .for(harmonySpecifierTag)
490
+ .tap(PLUGIN_NAME, (node, members) => {
491
+ const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
492
+ if (!isNamespaceMemberWrite(settings, members)) return;
493
+ const written = writeTargetOf(node);
494
+ if (written.type === "MemberExpression") {
495
+ assignmentTarget = written;
496
+ } else {
497
+ bailOutOfConcatenation();
498
+ }
499
+ });
419
500
  parser.hooks.expression
420
501
  .for(harmonySpecifierTag)
421
502
  .tap(PLUGIN_NAME, (expr) => {
@@ -443,6 +524,10 @@ class HarmonyImportDependencyParserPlugin {
443
524
  );
444
525
  dep.loc = parser.getLocation(expr);
445
526
  dep.call = parser.scope.inTaggedTemplateTag;
527
+ if (assignmentTarget === expr) {
528
+ dep.assignment = true;
529
+ assignmentTarget = undefined;
530
+ }
446
531
  parser.state.module.addDependency(dep);
447
532
  attachDependencyGuards(parser, dep);
448
533
  getInnerGraphUtils(parser.state.compilation).onUsage(
@@ -496,6 +581,10 @@ class HarmonyImportDependencyParserPlugin {
496
581
  (expr.range)[0]
497
582
  );
498
583
  dep.loc = parser.getLocation(expr);
584
+ if (assignmentTarget === expression) {
585
+ dep.assignment = true;
586
+ assignmentTarget = undefined;
587
+ }
499
588
  parser.state.module.addDependency(dep);
500
589
  attachDependencyGuards(parser, dep);
501
590
  getInnerGraphUtils(parser.state.compilation).onUsage(
@@ -564,19 +653,17 @@ class HarmonyImportDependencyParserPlugin {
564
653
  return true;
565
654
  }
566
655
  );
567
- // Per the TC39 import-defer spec, [[Set]] on a Module Namespace
568
- // Exotic Object returns false without triggering evaluation. The
569
- // default expressionMemberChain path produces `<importVar>.a.foo`
570
- // whose `.a` getter eagerly requires (and thus evaluates) the
571
- // deferred module. For top-level `ns.foo = value`, walk only the
572
- // bare `ns` identifier so it gets replaced with the deferred
573
- // namespace proxy (whose set trap returns false), and leave the
574
- // `.foo = value` part as plain code.
656
+ // `[[Set]]` on a Module Namespace returns false without evaluating, yet the
657
+ // member-chain path emits `<importVar>.a.foo`, whose getter evaluates. So
658
+ // only the bare `ns` is walked, leaving `.foo = value` as plain code.
575
659
  parser.hooks.assignMemberChain
576
660
  .for(harmonySpecifierTag)
577
661
  .tap(PLUGIN_NAME, (expression, members) => {
578
662
  const settings = /** @type {HarmonySettings} */ (parser.currentTagData);
579
663
  settings.used = true;
664
+ if (isNamespaceMemberWrite(settings, members)) {
665
+ assignmentTarget = /** @type {MemberExpression} */ (expression.left);
666
+ }
580
667
  if (!ImportPhaseUtils.isDefer(settings.phase)) return;
581
668
  if (expression.operator !== "=") return;
582
669
  if (members.length !== 1) return;
@@ -226,10 +226,9 @@ HarmonyImportSideEffectDependency.Template = class HarmonyImportSideEffectDepend
226
226
  if (ImportPhaseUtils.isDefer(dep.phase)) return;
227
227
  const connection = moduleGraph.getConnection(dep);
228
228
  if (!connection || !connection.isTargetActive(runtime)) return;
229
- // A hoisted body cannot be deferred, so its imports evaluate at their
230
- // own slots; calling from here would run them after everything hoisted
231
- // in between. Eagerness stops at one level: a module is generated
232
- // before its importers, so it never learns whether it is itself eager.
229
+ // A hoisted body cannot be deferred, so its imports evaluate in their own
230
+ // slots; calling from here would run them after everything hoisted in
231
+ // between. Eagerness stops at one level, generation order allowing no more.
233
232
  if (concatenationScope.isWrapped()) {
234
233
  initFragments.push(
235
234
  new InitFragment(
@@ -134,6 +134,8 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
134
134
  this.referencedPropertiesInDestructuring = undefined;
135
135
  /** @type {DependencyGuard[] | undefined} */
136
136
  this.branchGuards = undefined;
137
+ /** @type {undefined | boolean} this reference is an assignment target */
138
+ this.assignment = undefined;
137
139
  }
138
140
 
139
141
  // TODO webpack 6 remove
@@ -379,8 +381,9 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
379
381
  {
380
382
  name: ids,
381
383
  canMangle: true,
382
- // Need access the export value to trigger side effects for deferred module
383
- canInline: !ImportPhaseUtils.isDefer(this.phase)
384
+ // Need access the export value to trigger side effects for deferred module.
385
+ // An inlined literal cannot be an assignment target at all.
386
+ canInline: !this.assignment && !ImportPhaseUtils.isDefer(this.phase)
384
387
  }
385
388
  ]
386
389
  : Dependency.EXPORTS_OBJECT_REFERENCED;
@@ -473,6 +476,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
473
476
  write(this.usedByExports);
474
477
  write(this.referencedPropertiesInDestructuring);
475
478
  write(this.branchGuards);
479
+ write(this.assignment);
476
480
  super.serialize(context);
477
481
  }
478
482
 
@@ -495,6 +499,7 @@ class HarmonyImportSpecifierDependency extends HarmonyImportDependency {
495
499
  this.usedByExports = read();
496
500
  this.referencedPropertiesInDestructuring = read();
497
501
  this.branchGuards = read();
502
+ this.assignment = read();
498
503
  super.deserialize(context);
499
504
  }
500
505
  }
@@ -677,6 +682,15 @@ HarmonyImportSpecifierDependency.Template = class HarmonyImportSpecifierDependen
677
682
  deferredImport: ImportPhaseUtils.isDefer(dep.phase)
678
683
  }
679
684
  );
685
+ // Concatenation merges the binding into a plain local a write would
686
+ // succeed against. Routing the write at a getter-only property of a
687
+ // throwaway object restores the TypeError the namespace gave it.
688
+ if (dep.assignment) {
689
+ // the local binding, the one name here an export is free not to
690
+ // spell as an identifier: `import { "a-b" as ab }`
691
+ const holder = `{ get ${dep.name}() { return ${exportExpr}; } }`;
692
+ exportExpr = `${dep.asiSafe ? "" : ";"}(${holder}).${dep.name}`;
693
+ }
680
694
  }
681
695
  } else {
682
696
  super.apply(dep, source, templateContext);
@@ -498,11 +498,12 @@ const cloneTagWithUrl = (
498
498
  return isLink ? body : `${body}</script>`;
499
499
  };
500
500
 
501
- // ES5 `<link rel="modulepreload">` polyfill (Safari <17, Firefox <115, …):
502
- // on browsers without native support, fetch each modulepreload target with the
503
- // tag's own credentials/integrity so the pending module import reuses it. The
504
- // `.ep` guard makes it idempotent, and the observer catches any later-inserted
505
- // links. Emitted only when the target environment lacks native support.
501
+ // WHY: an ES5 `<link rel="modulepreload">` polyfill (Safari <17, Firefox <115,
502
+ // …). On a browser without native support, each modulepreload target is fetched
503
+ // with the tag's own credentials and integrity, so the pending module import
504
+ // reuses it. The `.ep` guard makes that idempotent and the observer catches any
505
+ // later-inserted link. Emitted only where the target environment lacks native
506
+ // support.
506
507
  const MODULEPRELOAD_POLYFILL = [
507
508
  "(function(){",
508
509
  'var s=document.createElement("link").relList;',
@@ -737,10 +738,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
737
738
  const dep = /** @type {HtmlEntryDependency} */ (dependency);
738
739
  const compilation = runtimeTemplate.compilation;
739
740
 
740
- // A `type: "html"` link points at another emitted page, not a JS/CSS
741
- // chunk: rewrite the attribute to that page's filename (resolved by
742
- // HtmlModulesPlugin once it's built) and emit no sibling tags — a page
743
- // link loads only itself.
741
+ // A `type: "html"` link points at another emitted page rather than a chunk,
742
+ // so rewrite the attribute to that page's filename and emit no siblings:
743
+ // a page link loads only itself.
744
744
  if (dep.elementKind === "html") {
745
745
  source.replace(
746
746
  dep.range[0],
@@ -764,21 +764,17 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
764
764
  const orderedChunks = getEntrypointChunksInLoadOrder(entrypoint);
765
765
  const entryChunk = orderedChunks[orderedChunks.length - 1];
766
766
 
767
- // `crossorigin` mirrors `output.crossOriginLoading` onto every injected
768
- // tag. Empty when the option is off or the originating tag already set
769
- // `crossorigin` (author value wins, flagged at parse time). Mirrors
770
- // webpack's runtime, which sets `crossOrigin` on chunk-loading scripts,
771
- // and matches Vite, which emits it on every injected script/stylesheet.
767
+ // Mirrors `output.crossOriginLoading` onto every injected tag, as webpack's
768
+ // runtime does for chunk-loading scripts. Empty when the option is off or
769
+ // the originating tag set `crossorigin` itself, since the author wins.
772
770
  const crossOrigin =
773
771
  crossOriginLoading && !dep.hasOwnCrossOrigin
774
772
  ? ` crossorigin="${crossOriginLoading}"`
775
773
  : "";
776
774
 
777
- // Per-chunk SRI: emit an `integrity` sentinel resolved late (after the
778
- // chunks' final bytes exist) by `resolveChunkIntegritySentinels`. Tags are
779
- // generated per HTML module, but one module can back pages with different
780
- // `integrity` options, so sentinels are emitted whenever any page wants SRI
781
- // and each page then resolves or strips them on emit.
775
+ // Per-chunk SRI emits an `integrity` sentinel resolved once the chunks'
776
+ // final bytes exist. One module can back pages with different `integrity`
777
+ // options, so every page emits them and strips its own on emit.
782
778
  const htmlOption = compilation.outputOptions.html;
783
779
  const integrityOn = getHtmlGenerator().hasIntegritySentinels(compilation);
784
780
  const inject =
@@ -948,11 +944,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
948
944
  ? ` integrity="${getHtmlGenerator().makeChunkIntegritySentinel(chunk, kind)}"`
949
945
  : "";
950
946
  if (kind === "css") {
951
- // A CSS chunk is always loaded via `<link rel="stylesheet">`.
952
- // Clone only when the entry tag is itself a native `<link
953
- // rel="stylesheet">` (so attributes like `media` carry over);
954
- // a `<script>` entry that imported CSS, or a custom element,
955
- // gets a freshly synthesized `<link>`.
947
+ // A CSS chunk always loads through `<link rel="stylesheet">`. Clone
948
+ // only when the entry tag is itself one, so `media` carries over;
949
+ // anything else gets a freshly synthesized `<link>`.
956
950
  if (isStylesheet && tagIsNative) {
957
951
  return cloneTagWithUrl(
958
952
  originalTag,
@@ -1004,10 +998,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1004
998
  // Parser-derived anchor (a source text scan would match `</head>` inside
1005
999
  // comments or raw text).
1006
1000
  const headClose = inject === "head" ? dep.headAnchor : -1;
1007
- // When the entry tag is already inside <head> (tagStart < headClose),
1008
- // inserting siblings at headClose would place them after the entry,
1009
- // reversing runtime-before-entry execution order for deferred scripts.
1010
- // Insert before the entry tag instead so the load order is preserved.
1001
+ // With the entry tag already inside `<head>`, inserting at `headClose`
1002
+ // would place siblings after it and reverse runtime-before-entry order
1003
+ // for deferred scripts. Insert before the entry tag instead.
1011
1004
  const headAt =
1012
1005
  headClose < 0
1013
1006
  ? -1
@@ -1018,29 +1011,24 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1018
1011
  let cssHtml = "";
1019
1012
  let cssAt = -1;
1020
1013
  if (isStylesheet) {
1021
- // `<link rel="stylesheet">` entries are CSS, but a shared/runtime
1022
- // JS-only chunk (e.g. `optimization.runtimeChunk`) can still sit in
1023
- // the entrypoint — only clone the `<link>` for siblings that actually
1024
- // produce a `.css` asset (mirrors the JS branch below), otherwise the
1025
- // link points at a non-existent `.css` file (a 404, or an empty
1026
- // `<style>` when inlined). Attributes like `media` still carry over.
1014
+ // WHY: a `<link rel="stylesheet">` entry is CSS, but a shared or runtime
1015
+ // JS-only chunk — `optimization.runtimeChunk`, say — can still sit in the
1016
+ // entrypoint, so the `<link>` is cloned only for siblings that actually
1017
+ // produce a `.css` asset, mirroring the JS branch below. Otherwise it
1018
+ // points at a `.css` file that does not exist: a 404, or an empty
1019
+ // `<style>` when inlined. Attributes such as `media` still carry over.
1027
1020
  for (let i = 0; i < orderedChunks.length - 1; i++) {
1028
1021
  if (chunkHasCss(orderedChunks[i], chunkGraph)) {
1029
1022
  siblings.push(buildSibling(orderedChunks[i], "css"));
1030
1023
  }
1031
1024
  }
1032
1025
  } else {
1033
- // CSS chunks are emitted before JS chunks so the cascade is set
1034
- // up before any script runs. Within CSS the order needs to match
1035
- // the source's import order — `entrypoint.chunks` alone doesn't
1036
- // give us that for arbitrary splitChunks layouts (splitChunks
1037
- // inserts each new chunk before the entry chunk via
1038
- // `insertChunk(_, before)`, so split CSS siblings end up in
1039
- // *reverse* of the order they were processed — exactly the
1040
- // html-webpack-plugin#1838 / mini-css-extract#959 symptom). We
1041
- // re-derive the order from the entrypoint's module post-order
1042
- // index, which mirrors the dependency walk and so reflects the
1043
- // import order.
1026
+ // WHY: splitChunks inserts each new chunk before the entry chunk, so
1027
+ // `entrypoint.chunks` hands back split CSS siblings in reverse of the
1028
+ // order they were processed — the html-webpack-plugin#1838 and
1029
+ // mini-css-extract#959 symptom. The order is re-derived from the
1030
+ // entrypoint's module post-order index, which follows the dependency
1031
+ // walk and so the source's import order.
1044
1032
  /** @type {{ chunk: Chunk, index: number, key: string }[]} */
1045
1033
  const cssChunkOrder = [];
1046
1034
  /** @type {Chunk[]} */
@@ -1060,18 +1048,14 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1060
1048
  key: cssChunkSortKey(chunk)
1061
1049
  });
1062
1050
  }
1063
- // Anything that isn't CSS-only stays on the JS lane, in the
1064
- // `orderedChunks` order — that preserves the runtime-first /
1065
- // vendor-before-entry invariant of `getEntrypointChunksInLoadOrder`.
1066
- // Chunks that produce no `.js` and no `.css` (e.g. wasm-only
1067
- // or asset-only) still get a `<script>` clone here so we
1068
- // keep prior behavior for users who relied on it.
1051
+ // Anything not CSS-only stays on the JS lane in `orderedChunks` order,
1052
+ // preserving the runtime-first invariant. A chunk emitting neither
1053
+ // `.js` nor `.css` still gets a clone, as it always has.
1069
1054
  if (hasJs || !hasCss) jsChunks.push(chunk);
1070
1055
  }
1071
- // If the entry chunk itself contains CSS (entry JS imports CSS
1072
- // without splitChunks separating it), fold it into the same CSS
1073
- // ordering so the entry-chunk `<link>` lands in the correct
1074
- // cascade position relative to sibling CSS chunks.
1056
+ // When the entry chunk carries CSS itself, fold it into the same
1057
+ // ordering so its `<link>` lands in the right cascade position
1058
+ // relative to the sibling CSS chunks.
1075
1059
  if (chunkHasCss(entryChunk, chunkGraph)) {
1076
1060
  cssChunkOrder.push({
1077
1061
  chunk: entryChunk,
@@ -1084,13 +1068,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1084
1068
  });
1085
1069
  }
1086
1070
  cssChunkOrder.sort(compareCssChunkOrder);
1087
- // Stylesheets always land in <head> when the page has one. A
1088
- // classic blocking script pins them ahead of itself (`cssAnchor`)
1089
- // so its execution never awaits later CSS; when every script is
1090
- // `defer`/module they go to the *end* of head, after the script
1091
- // tags — Vite's and html-webpack-plugin's order: the scripts
1092
- // start fetching earlier yet still execute after parsing and
1093
- // after pending stylesheets.
1071
+ // Stylesheets land in `<head>`. A classic blocking script pins them
1072
+ // ahead of itself, so it never awaits later CSS; with only `defer` and
1073
+ // module scripts they go last, which starts the script fetches earlier.
1094
1074
  cssAt =
1095
1075
  dep.headAnchor >= 0
1096
1076
  ? dep.cssAnchor >= 0 && dep.cssAnchor < dep.headAnchor
@@ -1116,15 +1096,15 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1116
1096
  if (cssHtml !== "" && dep.cssAnchor < 0) source.insert(cssAt, cssHtml);
1117
1097
  }
1118
1098
 
1119
- // Resource hints are opt-in — webpack already loads the initial chunks
1120
- // via parallel `<script>` tags, so there is no waterfall to prevent by
1121
- // default. `output.resourceHints` requests them: `true` preloads the
1122
- // entry's initial dependency chunks (runtime, vendor, split); an array
1123
- // or function adds custom hints (a function may spread the auto
1124
- // `defaultHints`). Only for extracted pages — a JS-string HTML export
1125
- // would embed the sentinels in the JS chunk. URL-referenced assets
1126
- // (fonts, images) carrying `webpackPrefetch` / `webpackPreload`
1127
- // (magic-comment or `parser.<type>.urlHints` rule) also emit here.
1099
+ // WHY: resource hints are opt-in, the initial chunks already loading
1100
+ // through parallel `<script>` tags, so there is no default waterfall to
1101
+ // prevent. `output.resourceHints` requests them: `true` preloads the entry's
1102
+ // initial dependency chunks (runtime, vendor, split), while an array or a
1103
+ // function adds custom ones and a function may spread the auto
1104
+ // `defaultHints`. Extracted pages only — a JS-string HTML export would embed
1105
+ // the sentinels in the JS chunk. A URL-referenced asset carrying
1106
+ // `webpackPrefetch` / `webpackPreload`, by magic comment or a
1107
+ // `parser.<type>.urlHints` rule, emits here too.
1128
1108
  const resourceHintResolver =
1129
1109
  ResourceHintPlugin.getCompilationResolver(compilation);
1130
1110
  const resourceHints = resourceHintResolver.hints;
@@ -1152,15 +1132,16 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1152
1132
 
1153
1133
  // === chunks channel — the entry's own initial dependency graph ===
1154
1134
  if (resourceHints !== undefined && resourceHints !== false) {
1155
- // The auto initial-graph preload as descriptors carrying their exact
1156
- // tag, built only when needed (`true`/`"prefetch"` emits them, a
1157
- // function may spread them). The entry chunk is skipped — it's
1158
- // already the `<script src>`. ESM uses `modulepreload` (fetch +
1159
- // parse), classic output `preload as="script"`, and `"prefetch"`
1160
- // opts into `<link rel="prefetch">` (idle-time fetch, no `as` / no
1161
- // `integrity` — the spec doesn't list them). Async `import()` chunks
1162
- // aren't covered here; use `module.parser.javascript.dynamicImport*`
1163
- // which routes through webpack's on-demand chunk-load runtime.
1135
+ // WHY: descriptors for the auto initial-graph preload, carrying their
1136
+ // exact tag and built only when needed — `true` or `"prefetch"` emits
1137
+ // them, and a function may spread them. The entry chunk is skipped, being
1138
+ // the `<script src>` already. ESM uses `modulepreload`, which fetches and
1139
+ // parses; classic output `preload as="script"`; and `"prefetch"` opts into
1140
+ // `<link rel="prefetch">`, an idle-time fetch with no `as` and no
1141
+ // `integrity`, which the spec does not list. An async `import()` chunk is
1142
+ // not covered here: that is
1143
+ // `module.parser.javascript.dynamicImport*`, which routes through
1144
+ // webpack's on-demand chunk-load runtime.
1164
1145
  const prefetchMode = resourceHints === "prefetch";
1165
1146
  const preloadMode = resourceHints === true;
1166
1147
  /** @type {"modulepreload" | "preload" | "prefetch"} */
@@ -1195,10 +1176,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1195
1176
  "javascript"
1196
1177
  )}"`
1197
1178
  : "";
1198
- // Mirror the entry tag's `nonce`/`crossorigin`/`referrerpolicy`
1199
- // (and `output.crossOriginLoading`) so the request matches the
1200
- // sibling `<script>`'s and the browser reuses it instead of
1201
- // fetching twice.
1179
+ // Mirror the entry tag's `nonce`, `crossorigin` and `referrerpolicy`,
1180
+ // so the request matches the sibling `<script>`'s and the browser
1181
+ // reuses it rather than fetching twice.
1202
1182
  const attrs = `${dep.copyableAttrsText}${crossOrigin}${integrityAttr}`;
1203
1183
  const tag = prefetchMode
1204
1184
  ? `<link rel="prefetch" href="${href}"${attrs}>`
@@ -1276,14 +1256,10 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1276
1256
  }
1277
1257
 
1278
1258
  // === assets channel — URL-referenced assets carrying `prefetch`/`preload` ===
1279
- // The plugin has already scanned the entrypoint's chunks × modules
1280
- // once and cached the URL/CSS/HTML asset deps for this entry name;
1281
- // consume that list here so this template doesn't repeat the walk.
1282
- // Each unique asset emits one `<link rel="prefetch|preload">` into
1283
- // the HTML `<head>`; the JS chunk-startup runtime skips it (no
1284
- // double `<link>` in DOM). URLs are sentinels resolved from asset
1285
- // codegen data during `HtmlModulesPlugin` render — the asset
1286
- // module might not have been codegen'd yet at this point.
1259
+
1260
+ // The plugin already walked the entrypoint once and cached this entry's
1261
+ // asset deps, so consume that list rather than repeat it. URLs stay
1262
+ // sentinels here: the asset module may not be codegen'd yet.
1287
1263
  const outputCrossOriginAttr = crossOriginLoading
1288
1264
  ? ` crossorigin="${crossOriginLoading}"`
1289
1265
  : "";
@@ -1324,12 +1300,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1324
1300
  finalHints.push(h);
1325
1301
  }
1326
1302
  }
1327
- // When the target environment lacks native `modulepreload` (an
1328
- // `output.environment` capability, like the JS-feature checks), append
1329
- // a tiny polyfill once per page so the hints still warm the cache there.
1330
- // `resourceHints.modulePreloadPolyfill` defaults from the target's
1331
- // modulepreload support (`output.environment.modulePreload`); `false`
1332
- // opts out (strict CSP).
1303
+ // Without native `modulepreload` the hints warm no cache, so append the
1304
+ // polyfill once per page. It defaults from the target's support, and
1305
+ // `false` opts out, which a strict CSP needs.
1333
1306
  if (
1334
1307
  rhOptions &&
1335
1308
  rhOptions.modulePreloadPolyfill &&
@@ -1339,10 +1312,9 @@ HtmlEntryDependency.Template = class HtmlEntryDependencyTemplate extends (
1339
1312
  polyfilledSources.add(source);
1340
1313
  finalHints.push(`<script>${MODULEPRELOAD_POLYFILL}</script>`);
1341
1314
  }
1342
- // Insert right after the `<head>` open tag (parser-derived) so the
1343
- // hints are the document's first fetches; fall back to the first
1344
- // blocking script (else the entry tag) when the page has no
1345
- // written `<head>` (e.g. an HTML fragment).
1315
+ // Insert just after the `<head>` open tag, so the hints are the first
1316
+ // fetches. A page with no written `<head>` falls back to the first
1317
+ // blocking script, else the entry tag.
1346
1318
  const hintAt =
1347
1319
  dep.headOpenEnd >= 0
1348
1320
  ? dep.headOpenEnd
@@ -112,10 +112,9 @@ HtmlInlineScriptDependency.Template = class HtmlInlineScriptDependencyTemplate e
112
112
  url = getHtmlGenerator().makeChunkUrlSentinel(chunk, "javascript");
113
113
  }
114
114
 
115
- // Insert ` src="…"` right after `<script` so the inline body is
116
- // served from the emitted chunk instead. The browser ignores the
117
- // remaining inline body once `src` is present, but we still clear
118
- // it below so the unprocessed JS doesn't ride along.
115
+ // Insert ` src="…"` just after `<script`, serving the body from the emitted
116
+ // chunk. The browser ignores an inline body beside `src`, but it is cleared
117
+ // below so the unprocessed JS does not ride along.
119
118
  source.insert(dep.insertPos, ` src="${url}"`);
120
119
  source.replace(dep.contentRange[0], dep.contentRange[1] - 1, "");
121
120
  }
@@ -127,10 +127,9 @@ HtmlInlineStyleDependency.Template = class HtmlInlineStyleDependencyTemplate ext
127
127
  }
128
128
  }
129
129
 
130
- // An attribute value was entity-decoded before parsing, so re-escape
131
- // the processed CSS to keep the surrounding markup valid in any
132
- // quoting context, and drop the trailing newline the CSS generator
133
- // appends so the rewritten attribute stays on one line.
130
+ // An attribute value was entity-decoded before parsing, so the processed CSS
131
+ // is re-escaped to keep the markup valid in any quoting context, and the
132
+ // generator's trailing newline dropped to keep it on one line.
134
133
  if (dep.inAttribute) {
135
134
  cssText = cssText
136
135
  .replace(TRAILING_WHITESPACE_REGEXP, "")
@@ -20,7 +20,7 @@ const ImportMetaContextDependency = require("./ImportMetaContextDependency");
20
20
  * } from "estree"
21
21
  */
22
22
  /** @import JavascriptParser, { Range } from "../javascript/JavascriptParser" */
23
- /** @import { ContextModuleOptions, ContextMode } from "../ContextModule" */
23
+ /** @import { ContextModuleOptions, ContextMode } from "../context/ContextModule" */
24
24
  /** @import { ChunkName } from "../Chunk" */
25
25
  /** @import { RawChunkGroupOptions } from "../ChunkGroup" */
26
26
  /** @import { RawReferencedExports, DependencyLocation } from "../Dependency" */
@@ -27,7 +27,7 @@ const getUnsupportedFeatureWarning = memoize(() =>
27
27
  require("../errors/UnsupportedFeatureWarning")
28
28
  );
29
29
 
30
- /** @import { ContextModuleOptions } from "../ContextModule" */
30
+ /** @import { ContextModuleOptions } from "../context/ContextModule" */
31
31
  /** @import JavascriptParser, { Range } from "../javascript/JavascriptParser" */
32
32
  /** @import { RawReferencedExports, DependencyLocation } from "../Dependency" */
33
33
  /**
@@ -93,11 +93,9 @@ const IMPORT_META_FIELDS = new Set([
93
93
  "webpackHot"
94
94
  ]);
95
95
 
96
- // Single source of truth for `import.meta` accesses that only exist in ES modules
97
- // and therefore mark a module as ESM (consumed by HarmonyDetectionParserPlugin).
98
- // `dirname`/`filename` are resolved by NodeStuffPlugin, the rest here. The webpack
99
- // pragmas `import.meta.webpackHot`/`webpackContext` are intentionally excluded:
100
- // they are usable in CommonJS modules and must not force ESM.
96
+ // The `import.meta` accesses that exist only in ES modules, and so mark one.
97
+ // `dirname` and `filename` are resolved by NodeStuffPlugin. The webpack pragmas
98
+ // are excluded: they work in CommonJS too and must not force ESM.
101
99
  const IMPORT_META_NAMES = [
102
100
  IMPORT_META,
103
101
  IMPORT_META_URL,
@@ -109,11 +107,11 @@ const IMPORT_META_NAMES = [
109
107
  IMPORT_META_RESOLVE
110
108
  ];
111
109
 
112
- // Ordering contract for import.meta parser hooks across plugins: ESM detection
113
- // (HarmonyDetectionParserPlugin, non-bailing) must observe every access before
114
- // any bailing replacement; the merged replacements here must run before
115
- // DefinePlugin object defines (default stage 0) and its nested destructuring
116
- // handler (stage 100).
110
+ // WHY: the ordering contract for the `import.meta` parser hooks across plugins.
111
+ // ESM detection (HarmonyDetectionParserPlugin, non-bailing) must observe every
112
+ // access before any bailing replacement, and the merged replacements here must
113
+ // run before DefinePlugin's object defines (default stage 0) and its nested
114
+ // destructuring handler (stage 100).
117
115
  const IMPORT_META_STAGE_ESM_DETECTION = -1000;
118
116
  const IMPORT_META_STAGE_REPLACEMENT = -100;
119
117