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
@@ -148,10 +148,9 @@ const createCompilationHooks = () => ({
148
148
 
149
149
  const PLUGIN_NAME = "HtmlModulesPlugin";
150
150
 
151
- // Built-in default favicon (the webpack logo). Referenced as a `file:` request
152
- // so `<link rel="icon">` in the synthetic wrapper flows through the normal
153
- // asset pipeline — emitted hashed, with the correct publicPath, no direct IO.
154
- // Resolved from `__filename` (a sibling of this module) — no `path` needed.
151
+ // Built-in default favicon, referenced as a `file:` request so the wrapper's
152
+ // `<link rel="icon">` flows through the normal asset pipeline: emitted hashed,
153
+ // with the right publicPath and no direct IO.
155
154
  const DEFAULT_FAVICON = new URL("./favicon.svg", pathToFileURL(__filename))
156
155
  .href;
157
156
 
@@ -506,10 +505,9 @@ class HtmlModulesPlugin {
506
505
  // several entries, so those can only be applied per emitted asset.
507
506
  /** @type {Map<string, OutputHtmlOptions>} */
508
507
  const htmlOptionsByEntry = new Map();
509
- // SRI sentinels are emitted while the page's HTML is generated, before the
510
- // owning entry is known, so any page asking for integrity turns them on for
511
- // all of them; pages that don't want SRI drop them again on emit. Authored
512
- // `.html` pages never reach the entry hook, hence the global seed.
508
+ // SRI sentinels are emitted before the owning entry is known, so one page
509
+ // asking for integrity turns them on for all and the rest drop them on emit.
510
+ // Authored `.html` pages never reach the entry hook, hence the global seed.
513
511
  let anyIntegrity = isIntegrityEnabled(
514
512
  globalHtmlOptions && globalHtmlOptions.integrity
515
513
  );
@@ -542,13 +540,9 @@ class HtmlModulesPlugin {
542
540
  return options;
543
541
  };
544
542
 
545
- // `output.html` (or an entry's `html`) wraps a non-HTML entry in a
546
- // synthetic HTML module so the existing pipeline injects its JS/CSS
547
- // chunks and applies the `template` option. `dependOn` ancestors are
548
- // injected first so the page loads the shared/runtime chunks before
549
- // the entry's own (see `collectHtmlEntryRequests`). `crossOriginLoading`
550
- // and SRI are applied to the injected tags centrally in
551
- // HtmlEntryDependency.
543
+ // `output.html` wraps a non-HTML entry in a synthetic HTML module, so the
544
+ // existing pipeline injects its chunks. `dependOn` ancestors go first, so the
545
+ // page loads shared and runtime chunks before the entry's own.
552
546
  EntryOptionPlugin.getHooks(compiler).entry.tap(
553
547
  PLUGIN_NAME,
554
548
  (context, name, desc) => {
@@ -623,19 +617,15 @@ class HtmlModulesPlugin {
623
617
  /** @type {Map<string, { content: string, source: import("webpack-sources").RawSource }>} */
624
618
  const sentinelResolvedSourceCache = new Map();
625
619
 
626
- // `<script src>` and `<link rel="modulepreload">` references collected
627
- // by HtmlParser become real compilation entries here. The `script`
628
- // and `script-module` groups are chained via a leader-only dependOn so
629
- // they share a runtime — the first entry of the group owns it and
630
- // every subsequent entry sets `dependOn: [leader]`. Modulepreload
631
- // entries are emitted as independent entries (no dependOn) so they
632
- // can never be imported as a runtime leader by a later script —
633
- // that's what keeps the "preload but don't execute" contract of
634
- // `<link rel="modulepreload">` intact.
635
- // Per-compilation state: the HTML modules seen during make (so
636
- // `finishMake` creates their entries without scanning the whole module
637
- // graph), the stylesheet entry names (read in `afterChunks`) and the html
638
- // options of every emitted page, keyed by its asset name.
620
+ // WHY: the `script` and `script-module` groups are chained through a
621
+ // leader-only `dependOn`, so they share a runtime: the group's first entry
622
+ // owns it and every later one sets `dependOn: [leader]`. A modulepreload
623
+ // entry is emitted independently, with no `dependOn`, so a later script can
624
+ // never import it as a runtime leader — which is what keeps the "preload but
625
+ // don't execute" contract of `<link rel="modulepreload">` intact.
626
+ // Per-compilation state: the HTML modules seen during make, so `finishMake`
627
+ // creates their entries without scanning the module graph, plus the
628
+ // stylesheet entry names and each emitted page's html options.
639
629
  /** @type {WeakMap<import("../Compilation"), { htmlModules: Set<Module>, stylesheetEntries: Set<string>, pendingNames: Map<string, PendingName>, htmlAssetOptions: Map<string, OutputHtmlOptions> }>} */
640
630
  const compilationState = new WeakMap();
641
631
  /**
@@ -665,11 +655,9 @@ class HtmlModulesPlugin {
665
655
  /** @type {Map<string, Module>} */
666
656
  const linkedPages = new Map();
667
657
 
668
- // Collect the entries an HTML module asks for. Only the script chains
669
- // (`script`, `script-module`) share a runtime via a leader-only
670
- // `dependOn`; `modulepreload`, `stylesheet` and `html` links are all
671
- // independent entries (a CSS or page entry must not chain into a JS
672
- // leader, or the chunk would mix unrelated outputs).
658
+ // Collect the entries an HTML module asks for. Only the script chains share
659
+ // a runtime, through a leader-only `dependOn`; chaining a CSS or page entry
660
+ // into a JS leader would mix unrelated outputs into one chunk.
673
661
  /** @type {(module: Module) => { context: string, request: string, name: string, dependOn: string[] | undefined }[]} */
674
662
  const collectEntrySpecs = (module) => {
675
663
  const { htmlEntries } = /** @type {HtmlModuleBuildInfo} */ (
@@ -808,10 +796,9 @@ class HtmlModulesPlugin {
808
796
  })
809
797
  );
810
798
  };
811
- // Seed with the HTML modules seen during make (config entries /
812
- // imports, fresh or cache-restored); linked pages are reached by
813
- // recursion above. Sorted because they are tracked in build-completion
814
- // order, which the names must not depend on.
799
+ // Seed with the HTML modules seen during make; linked pages are reached by
800
+ // the recursion above. Sorted because they are tracked in build-completion
801
+ // order, which the generated names must not depend on.
815
802
  const seeds = [...htmlModules].sort(compareModulesByIdentifier);
816
803
  Promise.all(seeds.map(processEntry)).then(() => {
817
804
  /** @type {Set<Module>} */
@@ -822,12 +809,11 @@ class HtmlModulesPlugin {
822
809
  });
823
810
 
824
811
  // `csp` injects a `<meta http-equiv="Content-Security-Policy">` and
825
- // `integrity` resolves the SRI sentinels — both once the page's inline
826
- // content is final (in `processAssets` below), per page, so an entry's
827
- // `html` can override them.
828
- // `"auto"` marks implicit enablement (no user rule for HTML files) — see
829
- // `applyExperimentsDefaults`. Only then loaders win over the built-in type
830
- // (e.g. html-webpack-plugin's template loader in its child compiler).
812
+ // `integrity` resolves the SRI sentinels, both per page once its inline
813
+ // content is final, so an entry's `html` can override them.
814
+
815
+ // `"auto"` marks implicit enablement, the one case where loaders win over
816
+ // the built-in type — see `applyExperimentsDefaults`.
831
817
  // TODO webpack 6: html defaults to `true`, drop this implicit-only fallback.
832
818
  const implicitlyEnabled = compiler.options.experiments.html === "auto";
833
819
  compiler.hooks.compilation.tap(
@@ -860,13 +846,12 @@ class HtmlModulesPlugin {
860
846
  compilation.hooks.succeedModule.tap(PLUGIN_NAME, trackHtmlModule);
861
847
  compilation.hooks.stillValidModule.tap(PLUGIN_NAME, trackHtmlModule);
862
848
 
863
- // Resolve integrity and inline sentinels after `RealContentHashPlugin`
864
- // so final bytes are in place. Only HTML pages carry these sentinels —
865
- // never JS chunks that embed an HTML string.
866
- // SRI only takes effect on a cross-origin subresource fetched
867
- // with CORS; without `output.crossOriginLoading` the browser
868
- // silently ignores `integrity` on cross-origin loads. Warn once
869
- // so a CDN deployment doesn't ship no-op integrity attributes.
849
+ // Resolve integrity and inline sentinels after `RealContentHashPlugin`,
850
+ // so final bytes are in place. Only HTML pages carry them.
851
+
852
+ // SRI takes effect only on a cross-origin subresource fetched with CORS,
853
+ // so without `output.crossOriginLoading` the browser ignores `integrity`.
854
+ // Warn once, rather than let a CDN deployment ship no-op attributes.
870
855
  if (anyIntegrity && !compilation.outputOptions.crossOriginLoading) {
871
856
  compilation.warnings.push(
872
857
  new WebpackError(
@@ -912,12 +897,9 @@ class HtmlModulesPlugin {
912
897
  inlinedFiles
913
898
  );
914
899
  }
915
- // `injectTags` (add tags), `transformTags` (mutate/move/remove the
916
- // page's own and injected tags), and CSP all run over a single
917
- // parse: collect the tags/anchors once, let the hooks act, then
918
- // render every edit — placement, attribute rewrites, moves,
919
- // removals, CSP hashes/nonce/meta — in one pass. Injected inline
920
- // `<script>`/`<style>` are hashed like the page's own.
900
+ // `injectTags`, `transformTags` and CSP all run over a single parse:
901
+ // collect the tags and anchors once, let the hooks act, then render
902
+ // every edit in one pass.
921
903
  const injected = await hooks.injectTags.promise([], {
922
904
  outputName: name,
923
905
  html: resolved
@@ -991,14 +973,9 @@ class HtmlModulesPlugin {
991
973
  }
992
974
  );
993
975
 
994
- // CSS entries created by `<link rel="stylesheet">` in HTML need
995
- // their `.css` filename set via `chunk.cssFilenameTemplate`
996
- // (the field `CssModulesPlugin.getChunkFilenameTemplate` reads).
997
- // Compilation only flows `options.filename` to `chunk.filenameTemplate`,
998
- // which controls JS emit — there's no entry-level `cssFilename`.
999
- // Set it ourselves after chunks are created so each stylesheet
1000
- // entry emits to a distinct file derived from `output.cssFilename`
1001
- // (or `output.cssChunkFilename` for non-initial CSS chunks).
976
+ // There is no entry-level `cssFilename`: Compilation flows
977
+ // `options.filename` only to `chunk.filenameTemplate`, which drives JS
978
+ // emit. So set `chunk.cssFilenameTemplate` here, once chunks exist.
1002
979
  compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
1003
980
  const { stylesheetEntries, pendingNames } = getState(compilation);
1004
981
  if (pendingNames.size === 0) return;
@@ -1057,10 +1034,9 @@ class HtmlModulesPlugin {
1057
1034
  StaticExportsDependency,
1058
1035
  new StaticExportsDependency.Template()
1059
1036
  );
1060
- // `ConstDependency` is used by HtmlParser to insert
1061
- // ` type="module"` into the rewritten <script> tag when
1062
- // `output.module` is on. Register its template so the HTML
1063
- // generator runs the insertion.
1037
+ // HtmlParser uses `ConstDependency` to insert ` type="module"` into a
1038
+ // rewritten `<script>` under `output.module`; its template has to be
1039
+ // registered for the HTML generator to run that insertion.
1064
1040
  compilation.dependencyTemplates.set(
1065
1041
  ConstDependency,
1066
1042
  new ConstDependency.Template()
@@ -1092,10 +1068,9 @@ class HtmlModulesPlugin {
1092
1068
  HtmlEntryDependency,
1093
1069
  new HtmlEntryDependency.Template()
1094
1070
  );
1095
- // Inline `<script>` content is bundled as its own entry — the
1096
- // same pipeline that handles `<script src>` — via a
1097
- // `data:text/javascript,...` request. The dependency
1098
- // template rewrites the original tag to `<script src=…>`.
1071
+ // Inline `<script>` content becomes its own entry through a
1072
+ // `data:text/javascript,...` request, the same pipeline as
1073
+ // `<script src>`; the template then rewrites the tag.
1099
1074
  compilation.dependencyFactories.set(
1100
1075
  HtmlInlineScriptDependency,
1101
1076
  normalModuleFactory
@@ -1104,11 +1079,9 @@ class HtmlModulesPlugin {
1104
1079
  HtmlInlineScriptDependency,
1105
1080
  new HtmlInlineScriptDependency.Template()
1106
1081
  );
1107
- // Inline `<style>` content is routed through the CSS pipeline
1108
- // as a `data:text/css` module. The dependency template reads
1109
- // the processed CSS text from the CSS module's code
1110
- // generation data (`css-text` channel set by CssGenerator
1111
- // when `exportType` is `"text"`).
1082
+ // Inline `<style>` content goes through the CSS pipeline as a
1083
+ // `data:text/css` module; the template reads the processed text
1084
+ // from the `css-text` code-generation channel.
1112
1085
  compilation.dependencyFactories.set(
1113
1086
  HtmlInlineStyleDependency,
1114
1087
  normalModuleFactory
@@ -1178,10 +1151,9 @@ class HtmlModulesPlugin {
1178
1151
  (result, module) => {
1179
1152
  if (module.type === HTML_MODULE_TYPE) {
1180
1153
  const [source, ...rest] = removeBOMFromResult(result);
1181
- // `applyTemplate` is a no-op unless `module.parser.html.template`
1182
- // is set. Running it here (where the returned source becomes the
1183
- // module's stored source) keeps the parser's dependency offsets
1184
- // and the generator's render base in sync.
1154
+ // Run here, where the returned source becomes the module's stored
1155
+ // source, so the parser's dependency offsets and the generator's
1156
+ // render base stay in sync.
1185
1157
  const parser = /** @type {HtmlParser} */ (module.parser);
1186
1158
 
1187
1159
  return [parser.applyTemplate(source, module), ...rest];
@@ -1191,35 +1163,20 @@ class HtmlModulesPlugin {
1191
1163
  }
1192
1164
  );
1193
1165
 
1194
- // Emit extracted `.html` files for any HTML module that opted
1195
- // into extraction. The opt-in is computed by
1196
- // `HtmlGenerator#_shouldExtract`: `module.generator.html.extract:
1197
- // true` always extracts, `false` never extracts, and when
1198
- // `extract` is unset the generator extracts iff the HTML module
1199
- // is a compilation entry — the iteration below picks up only
1200
- // modules whose generator reported the `html` source type, so
1201
- // that decision is honored implicitly. The HTML content is read
1202
- // from the generator's secondary `"html"` source type (see
1203
- // HtmlGenerator#generate). The filename template comes from
1204
- // `output.htmlFilename` (initial chunks) or
1205
- // `output.htmlChunkFilename` (non-initial chunks), mirroring
1206
- // the CSS pipeline. Path data follows the asset-module pattern —
1207
- // `module` + a relative source `filename`, with `chunk`
1208
- // intentionally omitted so `[name]` resolves to the HTML
1209
- // source's basename (e.g. `page` for `./page.html`) rather
1210
- // than the importing chunk's name (e.g. `main`). A per-module
1211
- // content hash is computed from the rewritten HTML so the
1212
- // template's `[contenthash]` placeholder works; the
1213
- // compilation hash is also forwarded so `[fullhash]` /
1214
- // `[hash]` work in user-supplied templates.
1215
-
1216
- // Sentinel-resolved content and its content hash depend only on
1217
- // the HTML-type module source — not on the chunk or output
1218
- // filename — yet `renderManifest` runs per `(chunk, module)`.
1219
- // Memoize so a module landing in multiple chunks resolves and
1220
- // hashes its sentinels once. Scoped to this compilation because
1221
- // sentinel resolution embeds chunk filenames, which change
1222
- // across rebuilds; weakly keyed by source so entries release.
1166
+ // WHY: emit extracted `.html` files for any HTML module that opted in.
1167
+ // `HtmlGenerator#_shouldExtract` computes that opt-in —
1168
+ // `module.generator.html.extract: true` always extracts, `false` never,
1169
+ // and unset extracts only a compilation entry — and the iteration below
1170
+ // picks up only modules whose generator reported the `html` source type,
1171
+ // so that decision is honoured implicitly. The filename comes from
1172
+ // `output.htmlFilename` for initial chunks and `output.htmlChunkFilename`
1173
+ // otherwise, mirroring the CSS pipeline, and the path data follows the
1174
+ // asset-module pattern with `chunk` deliberately left out, so `[name]`
1175
+ // resolves to the HTML source's basename rather than the chunk's.
1176
+
1177
+ // `renderManifest` runs per `(chunk, module)`, but resolved content and
1178
+ // its hash depend only on the module source, so memoize. Scoped to this
1179
+ // compilation, since resolution embeds chunk filenames.
1223
1180
  /** @type {WeakMap<import("webpack-sources").Source, { resolvedContent: string, contentHash: string }>} */
1224
1181
  const resolvedSentinelHashCache = new WeakMap();
1225
1182
 
@@ -1241,15 +1198,12 @@ class HtmlModulesPlugin {
1241
1198
  if (!placeholderSource) return undefined;
1242
1199
  let cached = resolvedSentinelHashCache.get(placeholderSource);
1243
1200
  if (cached === undefined) {
1244
- // Resolve chunk-URL sentinels *before* hashing so the HTML's
1245
- // `[contenthash]` invalidates with the referenced chunks'
1246
- // filenames. Inlined chunks have no URL, so tag their inline
1247
- // sentinels with the chunk content hash — that keeps the emitted
1248
- // bytes (and RealContentHashPlugin's later recompute)
1249
- // content-dependent, so the page hash tracks inlined content too.
1250
- // Asset URL sentinels (from `HtmlEntryDependency` resource-hint
1251
- // tags) resolve here too — deferred from template.apply so it
1252
- // doesn't race with asset-module codegen.
1201
+ // Resolve chunk-URL sentinels before hashing, so the page's
1202
+ // `[contenthash]` tracks the referenced chunks. An inlined chunk has
1203
+ // no URL, so its sentinel carries the chunk content hash instead.
1204
+
1205
+ // Asset URL sentinels resolve here rather than in `template.apply`,
1206
+ // which would race with asset-module codegen.
1253
1207
  const resolvedContent = getHtmlGenerator().resolveAssetUrlSentinels(
1254
1208
  getHtmlGenerator().embedInlineChunkHashes(
1255
1209
  getHtmlGenerator().resolveChunkUrlSentinels(
@@ -1345,9 +1299,8 @@ class HtmlModulesPlugin {
1345
1299
  compilation.hooks.renderManifest.tap(
1346
1300
  PLUGIN_NAME,
1347
1301
  (result, { chunk }) => {
1348
- // HMR's `HotUpdateChunk`s flow through the same hook
1349
- // but aren't real output chunks — extracting `.html`
1350
- // for them would create stray hot-update HTML files.
1302
+ // HMR's `HotUpdateChunk`s reach this hook but are not output chunks,
1303
+ // so extracting `.html` for them would emit stray hot-update files.
1351
1304
  // `CssModulesPlugin` early-returns for the same reason.
1352
1305
  if (chunk instanceof HotUpdateChunk) return result;
1353
1306
  const { chunkGraph } = compilation;
@@ -1361,12 +1314,13 @@ class HtmlModulesPlugin {
1361
1314
  const outputOptions = compilation.outputOptions;
1362
1315
  for (const module of modules) {
1363
1316
  const normalModule = /** @type {NormalModule} */ (module);
1364
- // `<iframe srcdoc>` modules expose `html` only so HtmlInlineHtmlDependency
1365
- // can write the processed markup back into the host attribute — they are
1366
- // never standalone pages. `generator.extract: "inline"` marks them so no
1367
- // `.html` file is emitted; without this they'd collide on the
1368
- // `data:text/html` → chunk-name path (every srcdoc module in a chunk would
1369
- // emit `<chunk>.html`). An O(1) flag check, not a scan.
1317
+ // WHY: an `<iframe srcdoc>` module exposes `html` only so that
1318
+ // `HtmlInlineHtmlDependency` can write the processed markup back
1319
+ // into the host attribute; it is never a standalone page.
1320
+ // `generator.extract: "inline"` marks it so no `.html` file is
1321
+ // emitted — without it they would collide on the `data:text/html`
1322
+ // to chunk-name path, every srcdoc module in a chunk emitting
1323
+ // `<chunk>.html`. An O(1) flag check rather than a scan.
1370
1324
  const generatorOptions = normalModule.generatorOptions;
1371
1325
  if (generatorOptions && generatorOptions.extract === "inline") {
1372
1326
  continue;
@@ -1376,11 +1330,9 @@ class HtmlModulesPlugin {
1376
1330
  if (!emit) continue;
1377
1331
  const { resolvedContent, contentHash, filename, info } = emit;
1378
1332
 
1379
- // Resolve any remaining `[webpack/auto]` placeholders to an undo
1380
- // path computed from the emitted HTML's location, so asset/chunk
1381
- // URLs stay relative to `output.path` even when the page emits into
1382
- // a subdirectory. A relative `<base href>` prepends `../`s so the
1383
- // base can't misdirect the rewritten URLs (see `HtmlParser`).
1333
+ // Resolve the remaining `[webpack/auto]` placeholders against the
1334
+ // emitted page's own location, so URLs stay relative to `output.path`
1335
+ // from a subdirectory. A relative `<base href>` prepends `../`s.
1384
1336
  const basePrefix =
1385
1337
  /** @type {HtmlModuleBuildInfo} */ (normalModule.buildInfo)
1386
1338
  .baseUrlPrefix || "";
@@ -1402,12 +1354,9 @@ class HtmlModulesPlugin {
1402
1354
  .split(autoPlaceholder)
1403
1355
  .join(undoPath);
1404
1356
  const finalSource = new RawSource(finalContent);
1405
- // The same HTML module can land in multiple chunks with different
1406
- // `htmlFilename`/`htmlChunkFilename` shapes → different `undoPath`s and
1407
- // final content for the same module id. Include the emitted filename in
1408
- // the asset cache key and the post-undo-path content in the hash so the
1409
- // asset cache can't reuse one variant's bytes at another variant's URL.
1410
- // Unchanged content reuses the memoized hash instead of re-digesting.
1357
+ // One module can land in several chunks whose filename shapes give
1358
+ // different undo paths, so the emitted filename joins the cache key
1359
+ // and the post-undo content the hash — else variants alias.
1411
1360
  const finalContentHash =
1412
1361
  finalContent === resolvedContent
1413
1362
  ? contentHash