webpack 5.110.3 → 5.111.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 (208) hide show
  1. package/README.md +5 -0
  2. package/lib/APIPlugin.js +23 -7
  3. package/lib/AutomaticPrefetchPlugin.js +1 -1
  4. package/lib/Cache.js +8 -3
  5. package/lib/CacheFacade.js +1 -1
  6. package/lib/CircularModulesPlugin.js +157 -55
  7. package/lib/CleanPlugin.js +2 -2
  8. package/lib/Compilation.js +320 -302
  9. package/lib/Compiler.js +209 -46
  10. package/lib/ContextModule.js +17 -81
  11. package/lib/ContextModuleFactory.js +1 -1
  12. package/lib/CopyPlugin.js +1054 -0
  13. package/lib/DefinePlugin.js +24 -8
  14. package/lib/ExternalModule.js +41 -14
  15. package/lib/FileSystemInfo.js +17 -14
  16. package/lib/FlagDependencyExportsPlugin.js +45 -21
  17. package/lib/HotModuleReplacementPlugin.js +53 -7
  18. package/lib/JavascriptMetaInfoPlugin.js +5 -3
  19. package/lib/MainTemplate.js +5 -1
  20. package/lib/Module.js +16 -7
  21. package/lib/MultiCompiler.js +1 -1
  22. package/lib/MultiWatching.js +1 -1
  23. package/lib/NormalModule.js +45 -12
  24. package/lib/NormalModuleFactory.js +1 -1
  25. package/lib/RuntimeGlobals.js +21 -7
  26. package/lib/RuntimeModule.js +28 -12
  27. package/lib/RuntimePlugin.js +30 -3
  28. package/lib/RuntimeTemplate.js +780 -475
  29. package/lib/SourceMapDevToolPlugin.js +1 -1
  30. package/lib/Watching.js +9 -0
  31. package/lib/WebpackOptionsApply.js +84 -91
  32. package/lib/asset/AssetGenerator.js +25 -8
  33. package/lib/asset/AssetModule.js +3 -0
  34. package/lib/asset/WebManifestParser.js +7 -5
  35. package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
  36. package/lib/cache/IdleFileCachePlugin.js +2 -2
  37. package/lib/cache/PackFileCacheStrategy.js +14 -1
  38. package/lib/config/browserslistTargetHandler.js +19 -0
  39. package/lib/config/defaults.js +86 -50
  40. package/lib/config/normalization.js +82 -12
  41. package/lib/config/target.js +10 -0
  42. package/lib/container/ContainerReferencePlugin.js +6 -0
  43. package/lib/container/RemoteRuntimeModule.js +9 -0
  44. package/lib/container/declaredRemotes.js +39 -0
  45. package/lib/css/CssGenerator.js +8 -0
  46. package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
  47. package/lib/css/CssLoadingRuntimeModule.js +94 -36
  48. package/lib/css/CssModule.js +1 -1
  49. package/lib/css/CssModulesPlugin.js +7 -6
  50. package/lib/css/CssParser.js +144 -11
  51. package/lib/css/CssServerStylesRuntimeModule.js +9 -0
  52. package/lib/css/cssMinify.js +11 -3
  53. package/lib/css/data.js +2814 -678
  54. package/lib/css/syntax.js +4082 -248
  55. package/lib/debug/ProfilingPlugin.js +4 -0
  56. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
  57. package/lib/dependencies/AMDRuntimeModules.js +18 -0
  58. package/lib/dependencies/CommonJsExportRequireDependency.js +3 -1
  59. package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
  60. package/lib/dependencies/CommonJsImportsParserPlugin.js +1 -0
  61. package/lib/dependencies/CommonJsPlugin.js +19 -3
  62. package/lib/dependencies/CommonJsRequireDependency.js +14 -5
  63. package/lib/dependencies/CssIcssExportDependency.js +7 -1
  64. package/lib/dependencies/HarmonyCompatibilityDependency.js +58 -4
  65. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -3
  66. package/lib/dependencies/HarmonyExportExpressionDependency.js +44 -29
  67. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +71 -13
  68. package/lib/dependencies/HarmonyExportInitFragment.js +99 -19
  69. package/lib/dependencies/HarmonyExportSpecifierDependency.js +18 -30
  70. package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
  71. package/lib/dependencies/HarmonyImportDependency.js +6 -1
  72. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +8 -1
  73. package/lib/dependencies/HarmonyImportSpecifierDependency.js +24 -1
  74. package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
  75. package/lib/dependencies/HtmlEntryDependency.js +50 -0
  76. package/lib/dependencies/ImportMetaMainDependency.js +104 -0
  77. package/lib/dependencies/ImportMetaPlugin.js +59 -15
  78. package/lib/dependencies/SystemRuntimeModule.js +9 -0
  79. package/lib/dependencies/WorkerDependency.js +1 -2
  80. package/lib/dependencies/WorkletDependency.js +1 -2
  81. package/lib/dll/DelegatedModule.js +18 -1
  82. package/lib/dll/DllReferencePlugin.js +11 -8
  83. package/lib/dll/LibManifestPlugin.js +1 -1
  84. package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
  85. package/lib/errors/DuplicateModulesWarning.js +12 -7
  86. package/lib/errors/EmptyCopyPatternWarning.js +26 -0
  87. package/lib/errors/ExternalStarReexportError.js +44 -0
  88. package/lib/errors/MissingSourceMapsWarning.js +36 -0
  89. package/lib/errors/ModuleParseError.js +2 -1
  90. package/lib/errors/UnusedAssetsWarning.js +36 -0
  91. package/lib/errors/UnusedFederationWarning.js +35 -0
  92. package/lib/errors/UnusedModulesWarning.js +38 -0
  93. package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
  94. package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
  95. package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
  96. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
  97. package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
  98. package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
  99. package/lib/html/HtmlGenerator.js +11 -5
  100. package/lib/html/HtmlModulesPlugin.js +331 -62
  101. package/lib/html/HtmlParser.js +13 -6
  102. package/lib/html/builtinEmbeddedRenderer.js +107 -0
  103. package/lib/html/data.js +121 -7
  104. package/lib/html/htmlMinify.js +84 -113
  105. package/lib/html/syntax.js +763 -426
  106. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  107. package/lib/index.js +3 -0
  108. package/lib/javascript/JavascriptModule.js +1 -0
  109. package/lib/javascript/JavascriptModulesPlugin.js +52 -24
  110. package/lib/javascript/JavascriptParser.js +1255 -728
  111. package/lib/javascript/StartupHelpers.js +27 -3
  112. package/lib/javascript/data.js +172 -0
  113. package/lib/javascript/grammar.js +5546 -0
  114. package/lib/javascript/parser.js +1494 -0
  115. package/lib/javascript/regexp.js +1762 -0
  116. package/lib/javascript/regexpData.js +51 -0
  117. package/lib/javascript/syntax.js +8696 -5225
  118. package/lib/library/ModuleLibraryPlugin.js +116 -5
  119. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
  120. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
  121. package/lib/optimize/ConcatenatedModule.js +97 -20
  122. package/lib/optimize/ConstExportsPlugin.js +50 -39
  123. package/lib/optimize/InlineExports.js +20 -123
  124. package/lib/optimize/MangleExportsPlugin.js +10 -0
  125. package/lib/optimize/ModuleConcatenationPlugin.js +24 -1
  126. package/lib/optimize/RealContentHashPlugin.js +68 -9
  127. package/lib/optimize/SideEffectsFlagPlugin.js +17 -9
  128. package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
  129. package/lib/performance/CacheEffectivenessPlugin.js +4 -3
  130. package/lib/performance/DuplicateModulesPlugin.js +57 -13
  131. package/lib/performance/EvalUsagePlugin.js +5 -2
  132. package/lib/performance/MissingSourceMapsPlugin.js +115 -0
  133. package/lib/performance/PureAnnotationsPlugin.js +6 -3
  134. package/lib/performance/TopLevelThisPlugin.js +5 -4
  135. package/lib/performance/UnusedAssetsPlugin.js +109 -0
  136. package/lib/performance/UnusedFederationPlugin.js +147 -0
  137. package/lib/performance/UnusedModulesPlugin.js +141 -0
  138. package/lib/performance/UnusedReexportsPlugin.js +1 -55
  139. package/lib/performance/isOnlyReexported.js +65 -0
  140. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
  141. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +2 -0
  142. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
  143. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
  144. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
  145. package/lib/prefetch/ResourceHintPlugin.js +1 -2
  146. package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
  147. package/lib/prefetch/StartupAssetHintRuntimeModule.js +9 -0
  148. package/lib/rules/RuleSetCompiler.js +211 -4
  149. package/lib/runtime/AsyncModuleRuntimeModule.js +100 -66
  150. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
  151. package/lib/runtime/BaseUriRuntimeModule.js +9 -0
  152. package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
  153. package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
  154. package/lib/runtime/GetChunkFilenameRuntimeModule.js +9 -0
  155. package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
  156. package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
  157. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
  158. package/lib/runtime/GlobalRuntimeModule.js +9 -0
  159. package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
  160. package/lib/runtime/HelperRuntimeModule.js +10 -0
  161. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +330 -219
  162. package/lib/runtime/NonceRuntimeModule.js +9 -0
  163. package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
  164. package/lib/runtime/PublicPathRuntimeModule.js +9 -0
  165. package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
  166. package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
  167. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
  168. package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
  169. package/lib/runtime/SystemContextRuntimeModule.js +9 -0
  170. package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
  171. package/lib/serialization/ObjectMiddleware.js +138 -106
  172. package/lib/sharing/ConsumeSharedPlugin.js +12 -0
  173. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
  174. package/lib/sharing/ShareRuntimeModule.js +9 -0
  175. package/lib/sharing/declaredShared.js +47 -0
  176. package/lib/stats/DefaultStatsFactoryPlugin.js +3 -1
  177. package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
  178. package/lib/util/SourceProcessor.js +76 -69
  179. package/lib/util/async.js +292 -0
  180. package/lib/util/buildDiagnostics.js +69 -0
  181. package/lib/util/fs.js +27 -1
  182. package/lib/util/handlerKeys.js +40 -0
  183. package/lib/util/identifier.js +20 -0
  184. package/lib/util/internalSerializables.js +4 -0
  185. package/lib/util/registerExternalSerializer.js +6 -45
  186. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
  187. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
  188. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +9 -0
  189. package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
  190. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
  191. package/package.json +22 -16
  192. package/schemas/WebpackOptions.check.js +1 -1
  193. package/schemas/WebpackOptions.json +379 -66
  194. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  195. package/schemas/plugins/ManifestPlugin.check.js +1 -1
  196. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  197. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  198. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  199. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  200. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  201. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  202. package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
  203. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
  204. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  205. package/types.d.ts +1414 -314
  206. package/lib/dependencies/ExportBindingInitFragment.js +0 -191
  207. package/lib/errors/EntrypointOverlapWarning.js +0 -45
  208. package/lib/performance/EntrypointOverlapPlugin.js +0 -122
@@ -9,14 +9,7 @@ const { CachedSource, ReplaceSource } = require("webpack-sources");
9
9
  const APIPlugin = require("./APIPlugin");
10
10
 
11
11
  const InitFragment = require("./InitFragment");
12
- const {
13
- ASSET_TYPE,
14
- ASSET_URL_TYPE,
15
- CSS_TYPE,
16
- HTML_TYPE,
17
- JAVASCRIPT_TYPE,
18
- RUNTIME_TYPE
19
- } = require("./ModuleSourceTypeConstants");
12
+ const { CSS_TYPE, JAVASCRIPT_TYPE } = require("./ModuleSourceTypeConstants");
20
13
  const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("./ModuleTypeConstants");
21
14
  const RuntimeGlobals = require("./RuntimeGlobals");
22
15
  const Template = require("./Template");
@@ -31,6 +24,7 @@ const { InlinedUsedName } = require("./optimize/InlineExports");
31
24
  const {
32
25
  getDeferredCycleModuleIds,
33
26
  getDeferredCycleModules,
27
+ getKnownExportNames,
34
28
  getMakeDeferredNamespaceModeFromExportsType,
35
29
  getOptimizedDeferredModule
36
30
  } = require("./runtime/MakeDeferredNamespaceObjectRuntime");
@@ -42,7 +36,11 @@ const { equals } = require("./util/ArrayHelpers");
42
36
  const { getScheme } = require("./util/URLAbsoluteSpecifier");
43
37
  const { compareIds } = require("./util/comparators");
44
38
  const compileBooleanMatcher = require("./util/compileBooleanMatcher");
45
- const { getUndoPath, toJsStringLiteral } = require("./util/identifier");
39
+ const {
40
+ RESOLVABLE_SPECIFIER_REGEXP,
41
+ getUndoPath,
42
+ toJsStringLiteral
43
+ } = require("./util/identifier");
46
44
  const memoize = require("./util/memoize");
47
45
  const { propertyAccess, propertyName } = require("./util/property");
48
46
  const {
@@ -92,6 +90,20 @@ const getTemplatedPathPlugin = memoize(() => require("./TemplatedPathPlugin"));
92
90
  const getConcatenatedModule = memoize(() =>
93
91
  require("./optimize/ConcatenatedModule")
94
92
  );
93
+ const getNormalModule = memoize(() => require("./NormalModule"));
94
+
95
+ /**
96
+ * Whether a hot update can re-run the module a reference is emitted into: the HMR
97
+ * plugin marks every normal module, and a concatenated one is read through its root.
98
+ * @param {Module | undefined} module the module a reference is emitted into
99
+ * @returns {boolean} true under HMR
100
+ */
101
+ const isHotModule = (module) => {
102
+ if (module === undefined) return false;
103
+ const normal =
104
+ module instanceof getConcatenatedModule() ? module.rootModule : module;
105
+ return normal instanceof getNormalModule() && normal.hot;
106
+ };
95
107
 
96
108
  // Any `[hash]`/`[fullhash]`/`[chunkhash]`/`[contenthash]` token, incl. a `:<length>`
97
109
  // or `:<digest>[:<length>]` suffix (e.g. `[contenthash:base64:8]`). Its value is only
@@ -104,6 +116,9 @@ const HASH_PROBE = "0123456789abcdef0123";
104
116
  const HASH_PROBE_ALTERNATE = "3210fedcba9876543210";
105
117
  const HASH_IN_FILENAME_GLOBAL = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/g;
106
118
 
119
+ // What a recorded reason is prefixed with in `stats.optimizationBailout`.
120
+ const ANALYZABLE_BAILOUT_PREFIX = "Analyzable ESM bailout: ";
121
+
107
122
  /**
108
123
  * @param {SpecifierPart} part one piece of a reserved name
109
124
  * @returns {boolean} true when it is text the deferred pass adds nothing to
@@ -156,21 +171,6 @@ const rootedParts = (parts) =>
156
171
  ]
157
172
  : parts;
158
173
 
159
- // Types that ride the chunk itself or render their own asset, so no `.f` handler
160
- // fetches them; every other type may install one, so the map has to exist for it.
161
- /** @type {Set<string>} */
162
- const TYPES_WITHOUT_CHUNK_HANDLER = new Set([
163
- JAVASCRIPT_TYPE,
164
- RUNTIME_TYPE,
165
- ASSET_TYPE,
166
- ASSET_URL_TYPE,
167
- HTML_TYPE
168
- ]);
169
-
170
- // Why a name only the deferred pass could settle was not deferred.
171
- const DEFER_BAILOUT =
172
- "a hashed name needs optimization.realContentHash, or no emitted javascript named by its content";
173
-
174
174
  /**
175
175
  * Where a literal is read from — the `../` path back to the output root, and whether
176
176
  * the chunk loader fetched the chunk it sits in through `output.publicPath`.
@@ -179,13 +179,6 @@ const DEFER_BAILOUT =
179
179
  * @property {boolean | null} loaded whether the chunk loader fetched the chunk
180
180
  */
181
181
 
182
- /**
183
- * @typedef {object} AnalyzableChunkUrls
184
- * @property {Map<ChunkId, string>} urls the urls that could be written, by chunk id
185
- * @property {boolean} complete false when some chunk kept the runtime form, whose
186
- * ids the consumer then still resolves through the runtime name lookup
187
- */
188
-
189
182
  /**
190
183
  * @typedef {object} WasmGroups
191
184
  * @property {(key: string) => string} groupOf the group a runtime key answers with
@@ -217,7 +210,12 @@ const RUNTIME_HASH_ROUND = 2;
217
210
 
218
211
  // Why a public path needing a base could not be spelled from the chunk holding it.
219
212
  const SERVED_BAILOUT =
220
- "this module is in a chunk webpack loads through output.publicPath and in one it does not, so no one path back to the output root fits both";
213
+ 'this module is in a chunk webpack loads through output.publicPath and in one it does not, so no one path back to the output root fits both (a root-absolute or absolute output.publicPath, or "auto", is read the same from both)';
214
+
215
+ // Why a runtime's url map kept the runtime form under HMR: an update re-ships the
216
+ // runtime module only when its own code changes.
217
+ const HOT_NAME_BAILOUT =
218
+ "a hot update can move this name without changing the runtime module that spells it, so the update would not carry the new one";
221
219
 
222
220
  /**
223
221
  * @import {
@@ -238,8 +236,9 @@ const SERVED_BAILOUT =
238
236
  * One piece of a name only the deferred pass can spell: text as it stands, the `../`
239
237
  * path from the asset it sits in to the output root, a template or `output.publicPath`
240
238
  * resolved once the hashes exist, one of the assets the chunk with this id emits, or
241
- * the base everything else is resolved against once it is spelled.
242
- * @typedef {"literal" | "undo" | "template" | "publicPath" | "unserved" | "chunk" | "cssChunk" | "base"} SpecifierPartKind
239
+ * the base everything else is resolved against once it is spelled. A `repair` part
240
+ * spells nothing: it marks a name the repair pass has to bring back in line.
241
+ * @typedef {"literal" | "undo" | "template" | "publicPath" | "unserved" | "chunk" | "cssChunk" | "base" | "repair"} SpecifierPartKind
243
242
  */
244
243
  /** @typedef {[SpecifierPartKind, string | number]} SpecifierPart */
245
244
 
@@ -251,7 +250,8 @@ const SPECIFIER_PART_KINDS = new Set([
251
250
  "unserved",
252
251
  "base",
253
252
  "chunk",
254
- "cssChunk"
253
+ "cssChunk",
254
+ "repair"
255
255
  ]);
256
256
 
257
257
  // Only these carry a chunk id, which is the one part value that may be a number.
@@ -262,7 +262,10 @@ const CHUNK_SPECIFIER_PART_KINDS = new Set(["chunk", "cssChunk"]);
262
262
  const FULL_HASH_PART_KINDS = new Set(["publicPath", "template", "unserved"]);
263
263
 
264
264
  // What the deferred pass scans for — the other half of what the class spells.
265
+ const ANALYZABLE_TOKEN_PREFIX = "./@@webpackAnalyzableChunk:";
265
266
  const ANALYZABLE_TOKEN_REGEXP = /\.\/@@webpackAnalyzableChunk:([\w-]+)@@/g;
267
+ // The same token read back out of one quoted specifier.
268
+ const ANALYZABLE_TOKEN_PAYLOAD = /@@webpackAnalyzableChunk:([\w-]+)@@/;
266
269
 
267
270
  // Stands in for the compilation hash inside an otherwise resolved filename, with the
268
271
  // requested length when the placeholder asked for one.
@@ -305,8 +308,7 @@ const PASS_NAME = "analyzableChunkNaming";
305
308
  /** @import { Source } from "webpack-sources" */
306
309
  /** @import Compiler from "./Compiler" */
307
310
  /** @import Chunk, { ChunkFilenameTemplate, ChunkId } from "./Chunk" */
308
- /** @import ChunkGroup from "./ChunkGroup" */
309
- /** @import ChunkGraph from "./ChunkGraph" */
311
+ /** @import ChunkGraph, { ModuleId } from "./ChunkGraph" */
310
312
  /** @import Compilation from "./Compilation" */
311
313
  /** @import Dependency from "./Dependency" */
312
314
  /** @import ModuleGraph from "./ModuleGraph" */
@@ -428,6 +430,43 @@ const isAsyncExternal = (/** @type {Module} */ module) =>
428
430
  Boolean(/** @type {BuildMeta} */ (module.buildMeta).async) &&
429
431
  module instanceof getExternalModule();
430
432
 
433
+ // `createFakeNamespaceObject`'s "merge all properties" bit, the only one that
434
+ // changes which names the namespace it builds carries.
435
+ const MERGE_PROPERTIES_MODE = 2;
436
+
437
+ /**
438
+ * The imported module decides, never the importer: two importers of one
439
+ * module have to be handed the same namespace object.
440
+ * @param {Module} module the imported module
441
+ * @returns {boolean} true when its namespace has to be a spec exotic object
442
+ */
443
+ const usesSpecNamespaceObject = (module) =>
444
+ Boolean(module.buildInfo && module.buildInfo.specNamespaceObject);
445
+
446
+ /**
447
+ * A module with no ESM namespace of its own — JSON, text, CommonJS — has one
448
+ * synthesized at each import site, so there the importer decides.
449
+ * @param {Module=} originModule the module the import is emitted into
450
+ * @returns {boolean} true when a namespace synthesized here has to be a spec object
451
+ */
452
+ const synthesizesSpecNamespaceObject = (originModule) =>
453
+ originModule !== undefined && usesSpecNamespaceObject(originModule);
454
+
455
+ /**
456
+ * Names the record a synthesized namespace belongs to and the shape it is built in,
457
+ * so every importer of one module reaches the same object and a reloaded module is
458
+ * not handed the namespace of the exports it replaced.
459
+ * @param {ModuleId | null} moduleId id of the imported module
460
+ * @param {number} mode the createFakeNamespaceObject mode the namespace is built with
461
+ * @returns {string} the arguments identifying it, ready to append to the call
462
+ */
463
+ const synthesizedNamespaceOwner = (moduleId, mode) =>
464
+ moduleId === null
465
+ ? ""
466
+ : `, ${RuntimeGlobals.moduleCache}[${JSON.stringify(moduleId)}], ${
467
+ mode & MERGE_PROPERTIES_MODE
468
+ }`;
469
+
431
470
  class RuntimeTemplate {
432
471
  /**
433
472
  * Creates an instance of RuntimeTemplate.
@@ -447,8 +486,8 @@ class RuntimeTemplate {
447
486
  (getGlobalObject(outputOptions.globalObject));
448
487
  /** @type {string} */
449
488
  this.contentHashReplacement = "X".repeat(outputOptions.hashDigestLength);
450
- /** @type {boolean | undefined} */
451
- this._javascriptNamedWithoutContent = undefined;
489
+ /** @type {Set<string>} */
490
+ this._analyzableRepairedAssets = new Set();
452
491
  /** @type {WeakMap<Chunk, boolean>} */
453
492
  this._chunkNamedWithoutContent = new WeakMap();
454
493
  /** @type {WeakMap<Chunk, string>} */
@@ -467,10 +506,18 @@ class RuntimeTemplate {
467
506
  this._publicPathClimbText = undefined;
468
507
  /** @type {WeakMap<Chunk, Placement>} */
469
508
  this._placementByChunk = new WeakMap();
509
+ /** @type {WeakMap<Chunk, string>} */
510
+ this._hotUpdateUndoByChunk = new WeakMap();
511
+ /** @type {string | undefined} */
512
+ this._hotUpdateShapeText = undefined;
470
513
  /** @type {Map<string, string | null | undefined>} */
471
514
  this._entryBaseUriByRuntime = new Map();
472
515
  /** @type {WasmGroups | undefined} */
473
516
  this._wasmGroupsValue = undefined;
517
+ /** @type {string[] | undefined} */
518
+ this._analyzableBailoutSink = undefined;
519
+ /** @type {Module | undefined} */
520
+ this._analyzableGeneratingModule = undefined;
474
521
  /** @type {Map<string, boolean> | undefined} */
475
522
  this._wasmAnchorKnownByGroup = undefined;
476
523
  }
@@ -569,6 +616,10 @@ class RuntimeTemplate {
569
616
  return this.outputOptions.environment.generator;
570
617
  }
571
618
 
619
+ supportsTopLevelAwait() {
620
+ return this.outputOptions.environment.topLevelAwait;
621
+ }
622
+
572
623
  supportsOptionalChaining() {
573
624
  return this.outputOptions.environment.optionalChaining;
574
625
  }
@@ -617,6 +668,41 @@ class RuntimeTemplate {
617
668
  return this.outputOptions.environment.modulePreload;
618
669
  }
619
670
 
671
+ /**
672
+ * Whether the deferred fill rewrote a chunk whose hashed name would otherwise go
673
+ * stale, which `RealContentHashPlugin` reads to run — and to repair `[chunkhash]`
674
+ * names — where `optimization.realContentHash` did not ask for it.
675
+ * @returns {boolean} true once the fill has marked such a chunk
676
+ */
677
+ needsAnalyzableRepair() {
678
+ return this._analyzableRepairedAssets.size > 0;
679
+ }
680
+
681
+ /**
682
+ * The assets the deferred fill rewrote under a name that has to be repaired: an
683
+ * on-demand repair renames only these and whatever names them.
684
+ * @returns {ReadonlySet<string>} their names
685
+ */
686
+ analyzableRepairedAssets() {
687
+ return this._analyzableRepairedAssets;
688
+ }
689
+
690
+ /**
691
+ * The `devtool` value wrapping a javascript module in `eval(...)`, read through both
692
+ * spellings — a plain string, and the per-asset-type array.
693
+ * @returns {string | undefined} the value, or undefined when no devtool wraps modules
694
+ */
695
+ _evalWrappingDevtool() {
696
+ const { devtool } = this.compilation.options;
697
+ const items = Array.isArray(devtool)
698
+ ? devtool
699
+ : [{ type: "all", use: devtool }];
700
+ for (const { type, use } of items) {
701
+ if (type !== "all" && type !== "javascript") continue;
702
+ if (typeof use === "string" && use.includes("eval")) return use;
703
+ }
704
+ }
705
+
620
706
  /**
621
707
  * Whether a reference a foreign bundler can follow without running webpack's runtime
622
708
  * may be emitted — the one question every caller asks, in the form it is asking for:
@@ -666,7 +752,8 @@ class RuntimeTemplate {
666
752
  APIPlugin.runtimeUsesPublicPathOverride(
667
753
  this.compilation,
668
754
  scoped ? chunkGraph : undefined,
669
- placedModule
755
+ placedModule,
756
+ runtime
670
757
  )
671
758
  ) {
672
759
  return this._analyzableBailout(
@@ -678,36 +765,12 @@ class RuntimeTemplate {
678
765
 
679
766
  if (form === "import") {
680
767
  // Read through a native `import()`, or it is not this feature at all.
681
- if (outputOptions.chunkFormat !== "module") {
682
- return this._analyzableBailout(
683
- module,
684
- `output.chunkFormat is ${JSON.stringify(outputOptions.chunkFormat)}, so chunks are not read through a native import()`,
685
- false
686
- );
687
- }
688
- if (outputOptions.importFunctionName !== "import") {
689
- return this._analyzableBailout(
690
- module,
691
- `output.importFunctionName is ${JSON.stringify(outputOptions.importFunctionName)}, so the call site is not a native import()`,
692
- false
693
- );
694
- }
695
- // A worker loading its own chunks some other way keeps that runtime; one on
696
- // `import` uses the same ESM loader as the main graph, so it can be analyzable.
697
- for (const originChunk of /** @type {ChunkGraph} */ (
698
- chunkGraph
699
- ).getModuleChunksIterable(/** @type {Module} */ (placedModule))) {
700
- const entryOptions = originChunk.getEntryOptions();
701
- if (!entryOptions || !entryOptions.worker) continue;
702
- // `WorkerAndWorkletPlugin` always seeds this from `output.workerChunkLoading`.
703
- if (entryOptions.chunkLoading !== "import") {
704
- return this._analyzableBailout(
705
- module,
706
- `this worker loads its chunks with ${JSON.stringify(entryOptions.chunkLoading)}, not "import"`,
707
- false
708
- );
709
- }
768
+ const outputReason = this._chunkImportOutputReason();
769
+ if (outputReason !== null) {
770
+ return this._analyzableBailout(module, outputReason, false);
710
771
  }
772
+ // A worker loading its own chunks some other way needs no answer here: it gets
773
+ // a chunk loader of its own, and only the ESM one asks this.
711
774
  return true;
712
775
  }
713
776
 
@@ -720,15 +783,12 @@ class RuntimeTemplate {
720
783
  if (form === "url-inline") return true;
721
784
  // `eval` devtool wraps each module in `eval(...)`, where `import.meta` is a
722
785
  // syntax error. Runtime modules are emitted beside them, never wrapped.
723
- const { devtool } = this.compilation.options;
724
- if (
725
- form !== "url-runtime" &&
726
- typeof devtool === "string" &&
727
- devtool.includes("eval")
728
- ) {
786
+ const evalDevtool =
787
+ form === "url-runtime" ? undefined : this._evalWrappingDevtool();
788
+ if (evalDevtool !== undefined) {
729
789
  return this._analyzableBailout(
730
790
  module,
731
- `devtool ${JSON.stringify(devtool)} wraps the module in eval(), where import.meta does not parse`,
791
+ `devtool ${JSON.stringify(evalDevtool)} wraps the module in eval(), where import.meta does not parse`,
732
792
  false
733
793
  );
734
794
  }
@@ -746,14 +806,14 @@ class RuntimeTemplate {
746
806
 
747
807
  // The rest is the `"wasm"` form: whether the whole binary url can be spelled
748
808
  // here, rather than built at runtime under an `import.meta.url` base.
749
- const { publicPath, webassemblyModuleFilename } = outputOptions;
809
+ const { publicPath } = outputOptions;
750
810
  if (publicPath !== "auto") {
751
811
  // A public path that needs no base names the same place from the chunk as from
752
812
  // the document, so a literal spells what `fetch` would have reached.
753
813
  if (this._publicPathNeedsNoBase()) {
754
814
  // Settled no earlier than the hash it reads or is called with, so it is
755
815
  // baked only where the deferred pass may finish it.
756
- if (this._resolvePublicPathPrefix(publicPath, module) === null) {
816
+ if (this._resolvePublicPathPrefix(publicPath) === null) {
757
817
  return false;
758
818
  }
759
819
  } else if (
@@ -767,17 +827,6 @@ class RuntimeTemplate {
767
827
  );
768
828
  }
769
829
  }
770
- // The compilation hash is settled after code generation, so a name carrying one
771
- // is baked only where the deferred pass can fill it in. `[hash]` is the module's
772
- // own here, which code generation already knows.
773
- if (
774
- getTemplatedPathPlugin()
775
- .getPresentKinds(/** @type {string} */ (webassemblyModuleFilename))
776
- .has("fullhash") &&
777
- !this._canDeferOrBakeFullHash(true, undefined, module)
778
- ) {
779
- return false;
780
- }
781
830
  return true;
782
831
  }
783
832
 
@@ -796,38 +845,97 @@ class RuntimeTemplate {
796
845
  */
797
846
  _analyzableBailout(module, reason, answer) {
798
847
  if (module !== undefined && this.outputOptions.module) {
799
- const text = `Analyzable ESM bailout: ${reason}`;
848
+ // Recorded on the module whose code is being generated, which is the one a
849
+ // cached result is restored for — an inner module of a concatenation is not.
850
+ const target = this._analyzableGeneratingModule || module;
851
+ const text = `${ANALYZABLE_BAILOUT_PREFIX}${reason}`;
800
852
  const bailouts =
801
- this.compilation.moduleGraph.getOptimizationBailout(module);
853
+ this.compilation.moduleGraph.getOptimizationBailout(target);
802
854
  if (!bailouts.includes(text)) bailouts.push(text);
855
+ // Each generation records its own: another runtime's result may be all the
856
+ // cache restores later, so what the graph holds must not hide a reason.
857
+ if (this._analyzableGeneratingModule !== undefined) {
858
+ // The sink exists only once a reason is recorded, so a module that
859
+ // bakes every reference — nearly all of them — allocates nothing here.
860
+ const sink =
861
+ this._analyzableBailoutSink || (this._analyzableBailoutSink = []);
862
+ if (!sink.includes(reason)) sink.push(reason);
863
+ }
803
864
  }
804
865
  return answer;
805
866
  }
806
867
 
807
868
  /**
808
- * Whether a name that code generation cannot settle may be reserved as a stand-in
809
- * and filled in once the hashes exist. Substituting rewrites a chunk after its own
810
- * content hash was taken, so either `RealContentHashPlugin` has to bring the two
811
- * back in line, or no emitted javascript may be named by its content in the first
812
- * place — with a name like `[name].js` there is nothing to go stale. Asked of the
813
- * names the chunks actually carry rather than of `output`, so a template nothing is
814
- * emitted under does not rule the rewrite out and a `chunk.filenameTemplate` does
815
- * not slip past it.
816
- * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into; omit
817
- * where the answer has to hold for the whole compilation, as it does for a gate a
818
- * runtime module asks from the other end
819
- * @returns {boolean} true when deferring is safe
869
+ * Names the module whose code generation starts, so the reasons its references
870
+ * record are handed back by `finishAnalyzableBailouts` and attributed to it.
871
+ * @param {Module} module the module being generated
872
+ * @returns {void}
820
873
  */
821
- _canDeferAnalyzableName(chunks) {
822
- if (chunks === undefined) {
823
- // Memoized: the chunk graph is settled before any caller asks compilation-wide.
824
- if (this._javascriptNamedWithoutContent === undefined) {
825
- this._javascriptNamedWithoutContent = this._canDeferAnalyzableName(
826
- this.compilation.chunks
827
- );
874
+ beginAnalyzableBailouts(module) {
875
+ this._analyzableGeneratingModule = module;
876
+ }
877
+
878
+ /**
879
+ * Ends the collection `beginAnalyzableBailouts` started, so the reasons can be
880
+ * stored beside the result and reapplied when the cache restores it.
881
+ * @returns {string[] | undefined} the reasons recorded since, or undefined for none
882
+ */
883
+ finishAnalyzableBailouts() {
884
+ const sink = this._analyzableBailoutSink;
885
+ this._analyzableGeneratingModule = undefined;
886
+ this._analyzableBailoutSink = undefined;
887
+ return sink;
888
+ }
889
+
890
+ /**
891
+ * Reapplies the bailouts a cached code generation result was stored with, so a
892
+ * restored module reports the same reasons a generated one does.
893
+ * @param {Module} module the module the result was restored for
894
+ * @param {string[]} reasons the reasons stored beside it
895
+ * @returns {void}
896
+ */
897
+ restoreAnalyzableBailouts(module, reasons) {
898
+ const bailouts =
899
+ this.compilation.moduleGraph.getOptimizationBailout(module);
900
+ for (const reason of reasons) {
901
+ const text = `${ANALYZABLE_BAILOUT_PREFIX}${reason}`;
902
+ if (!bailouts.includes(text)) bailouts.push(text);
903
+ }
904
+ }
905
+
906
+ /**
907
+ * The reasons a module's references keep the runtime form, as recorded while its
908
+ * code was generated.
909
+ * @param {Module} module the module, a runtime module included
910
+ * @returns {string[]} the reasons, none where every reference bakes
911
+ */
912
+ analyzableBailoutsOf(module) {
913
+ /** @type {string[]} */
914
+ const reasons = [];
915
+ for (const text of this.compilation.moduleGraph.getOptimizationBailout(
916
+ module
917
+ )) {
918
+ if (
919
+ typeof text === "string" &&
920
+ text.startsWith(ANALYZABLE_BAILOUT_PREFIX)
921
+ ) {
922
+ reasons.push(text.slice(ANALYZABLE_BAILOUT_PREFIX.length));
828
923
  }
829
- return this._javascriptNamedWithoutContent;
830
924
  }
925
+ return reasons;
926
+ }
927
+
928
+ /**
929
+ * Whether a name that code generation cannot settle may be reserved as a stand-in
930
+ * and filled in once the hashes exist without a repair behind it. Substituting
931
+ * rewrites a chunk after its own content hash was taken, so either no emitted
932
+ * javascript may be named by its content — with a name like `[name].js` there is
933
+ * nothing to go stale — or `RealContentHashPlugin` has to bring the two back in
934
+ * line, which is what a name this says no to gets: see `_needsRepair`.
935
+ * @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
936
+ * @returns {boolean} true when no name moves with the bytes the fill leaves
937
+ */
938
+ _canDeferAnalyzableName(chunks) {
831
939
  let found = false;
832
940
  for (const chunk of chunks) {
833
941
  found = true;
@@ -838,15 +946,15 @@ class RuntimeTemplate {
838
946
  }
839
947
 
840
948
  /**
841
- * `_canDeferAnalyzableName`, recording why not when the answer is no — what every
842
- * caller with a module to report against does with it.
843
- * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into
844
- * @param {Module=} module the module the reference is emitted into
845
- * @returns {boolean} true when deferring is safe
949
+ * Whether a stand-in written into `chunks` needs the repair pass behind it: their
950
+ * hashed names would otherwise go stale once the fill moves their bytes. The pass
951
+ * is `RealContentHashPlugin`, run on demand where `optimization.realContentHash`
952
+ * did not ask for it, and repairing `[chunkhash]` names too while it is at it.
953
+ * @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
954
+ * @returns {boolean} true when the fill has to mark the name for repair
846
955
  */
847
- _canDeferOrBail(chunks, module) {
848
- if (this._canDeferAnalyzableName(chunks)) return true;
849
- return this._analyzableBailout(module, DEFER_BAILOUT, false);
956
+ _needsRepair(chunks) {
957
+ return !this._canDeferAnalyzableName(chunks);
850
958
  }
851
959
 
852
960
  /**
@@ -854,37 +962,28 @@ class RuntimeTemplate {
854
962
  * and a stand-in for the deferred pass where they do not.
855
963
  * @param {SpecifierPart[]} parts the whole specifier
856
964
  * @param {Iterable<Chunk>} chunks the chunks it is written into
857
- * @param {Module=} module the module the reference is emitted into
858
- * @returns {string | null} it already quoted, or `null` when no stand-in may be
859
- * reserved
965
+ * @returns {string} it already quoted
860
966
  */
861
- _specifierOf(parts, chunks, module) {
967
+ _specifierOf(parts, chunks) {
862
968
  const text = literalText(parts);
863
969
  if (text !== null) return toJsStringLiteral(text);
864
- if (
865
- !this._canDeferOrBakeFullHash(
866
- this._partsBakeFullHash(parts),
867
- chunks,
868
- module
869
- )
870
- ) {
871
- return null;
872
- }
873
- return toJsStringLiteral(this._reserveAnalyzableSpecifier(parts));
970
+ // One built out of the compilation hash moves its chunk into the round after
971
+ // that hash, where the name is taken from the filled bytes anyway.
972
+ const repair = !this._partsBakeFullHash(parts) && this._needsRepair(chunks);
973
+ return toJsStringLiteral(
974
+ this._reserveAnalyzableSpecifier(this._markedForRepair(repair, parts))
975
+ );
874
976
  }
875
977
 
876
978
  /**
877
- * `_canDeferOrBail` for a name the fill builds out of the compilation hash. Such a
878
- * stand-in settles the name it lands in for us: `_markChunksBakingFullHash` reads it
879
- * back and moves that chunk into the round after that hash, which is the same place a
880
- * chunk reaching for `__webpack_require__.p` ends up without asking.
881
- * @param {boolean} carriesFullHash whether the fill builds this one out of that hash
882
- * @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into
883
- * @param {Module=} module the module the reference is emitted into
884
- * @returns {boolean} true when deferring is safe
979
+ * The parts a stand-in is reserved with, marked where the name it lands in has to
980
+ * be repaired after the fill.
981
+ * @param {boolean} repair what `_needsRepair` answered
982
+ * @param {SpecifierPart[]} parts what the stand-in resolves to
983
+ * @returns {SpecifierPart[]} the parts, marked where the repair is needed
885
984
  */
886
- _canDeferOrBakeFullHash(carriesFullHash, chunks, module) {
887
- return carriesFullHash || this._canDeferOrBail(chunks, module);
985
+ _markedForRepair(repair, parts) {
986
+ return repair ? [["repair", ""], ...parts] : parts;
888
987
  }
889
988
 
890
989
  /**
@@ -1023,7 +1122,7 @@ class RuntimeTemplate {
1023
1122
  );
1024
1123
  }
1025
1124
  const chunks = this._moduleChunks(module, chunkGraph);
1026
- const parts = this._resolvePublicPathPrefix(publicPath, module, chunks);
1125
+ const parts = this._resolvePublicPathPrefix(publicPath);
1027
1126
  if (parts === null) return null;
1028
1127
  // A protocol-relative base names a host but no scheme, and the runtime reads it
1029
1128
  // against the chunk's own url to get one — the very url this literal is
@@ -1032,8 +1131,7 @@ class RuntimeTemplate {
1032
1131
  if (base.startsWith("//")) {
1033
1132
  return this._specifierOf(
1034
1133
  [["literal", base], ...rootedParts(parts), ["literal", filename]],
1035
- chunks,
1036
- module
1134
+ chunks
1037
1135
  );
1038
1136
  }
1039
1137
  if (!isAbsoluteBaseUri(base)) {
@@ -1065,13 +1163,14 @@ class RuntimeTemplate {
1065
1163
  );
1066
1164
  }
1067
1165
  if (text !== null) return toJsStringLiteral(resolved.href);
1068
- if (!this._canDeferOrBail(chunks, module)) return null;
1069
1166
  return toJsStringLiteral(
1070
- this._reserveAnalyzableSpecifier([
1071
- ["base", base],
1072
- ...parts,
1073
- ["literal", filename]
1074
- ])
1167
+ this._reserveAnalyzableSpecifier(
1168
+ this._markedForRepair(this._needsRepair(chunks), [
1169
+ ["base", base],
1170
+ ...parts,
1171
+ ["literal", filename]
1172
+ ])
1173
+ )
1075
1174
  );
1076
1175
  }
1077
1176
 
@@ -1868,14 +1967,21 @@ class RuntimeTemplate {
1868
1967
  });
1869
1968
  const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
1870
1969
  switch (exportsType) {
1871
- case "namespace":
1872
- return this.moduleRaw({
1970
+ case "namespace": {
1971
+ const raw = this.moduleRaw({
1873
1972
  module,
1874
1973
  chunkGraph,
1875
1974
  request,
1876
1975
  weak,
1877
1976
  runtimeRequirements
1878
1977
  });
1978
+
1979
+ if (!usesSpecNamespaceObject(module)) return raw;
1980
+
1981
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
1982
+
1983
+ return `${RuntimeGlobals.specNamespaceObject}(${raw})`;
1984
+ }
1879
1985
  case "default-with-named":
1880
1986
  runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1881
1987
  return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`;
@@ -1984,6 +2090,21 @@ class RuntimeTemplate {
1984
2090
 
1985
2091
  let mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
1986
2092
  if (mode) mode = `${mode} | 16`;
2093
+ // The spec's namespace keys are the sorted exports, so hand them over
2094
+ // when they are fully known; otherwise the runtime stays permissive.
2095
+ const deferredExportNames = getKnownExportNames(
2096
+ chunkGraph.moduleGraph,
2097
+ module,
2098
+ exportsType
2099
+ );
2100
+ runtimeRequirements.add(
2101
+ deferredExportNames
2102
+ ? RuntimeGlobals.hasSealedDeferredNamespace
2103
+ : RuntimeGlobals.hasSynthesizedDeferredNamespace
2104
+ );
2105
+ mode += deferredExportNames
2106
+ ? `, ${JSON.stringify(deferredExportNames)}`
2107
+ : "";
1987
2108
 
1988
2109
  const asyncDeps = Array.from(
1989
2110
  getOutgoingAsyncModules(chunkGraph.moduleGraph, module),
@@ -2027,15 +2148,22 @@ class RuntimeTemplate {
2027
2148
  } else {
2028
2149
  let fakeType = 16;
2029
2150
  switch (exportsType) {
2030
- case "namespace":
2031
- if (header) {
2032
- const rawModule = this.moduleRaw({
2151
+ case "namespace": {
2152
+ const specNamespace = usesSpecNamespaceObject(module);
2153
+ const asyncModule = chunkGraph.moduleGraph.isAsync(module);
2154
+ if (header || (specNamespace && !asyncModule)) {
2155
+ let rawModule = this.moduleRaw({
2033
2156
  module,
2034
2157
  chunkGraph,
2035
2158
  request,
2036
2159
  weak,
2037
2160
  runtimeRequirements
2038
2161
  });
2162
+ if (specNamespace && !asyncModule) {
2163
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2164
+ // Wrap before promise resolution assimilates an exported `then`.
2165
+ rawModule = `${RuntimeGlobals.specNamespaceObject}(${rawModule})`;
2166
+ }
2039
2167
  appending = `.then(${this.basicFunction(
2040
2168
  "",
2041
2169
  `${header}return ${rawModule};`
@@ -2047,7 +2175,14 @@ class RuntimeTemplate {
2047
2175
  `${comment}${idExpr}`
2048
2176
  )})`;
2049
2177
  }
2178
+
2179
+ if (specNamespace && asyncModule) {
2180
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2181
+ appending += `.then(${RuntimeGlobals.specNamespaceObject})`;
2182
+ }
2183
+
2050
2184
  break;
2185
+ }
2051
2186
  case "dynamic":
2052
2187
  fakeType |= 4;
2053
2188
  /* fall through */
@@ -2101,6 +2236,15 @@ class RuntimeTemplate {
2101
2236
  )})`;
2102
2237
  }
2103
2238
  }
2239
+ if (synthesizesSpecNamespaceObject(originModule)) {
2240
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2241
+ runtimeRequirements.add(RuntimeGlobals.moduleCache);
2242
+ const owner = synthesizedNamespaceOwner(moduleId, fakeType);
2243
+ appending += `.then(${this.returningFunction(
2244
+ `${RuntimeGlobals.specNamespaceObject}(m${owner})`,
2245
+ "m"
2246
+ )})`;
2247
+ }
2104
2248
  break;
2105
2249
  }
2106
2250
  }
@@ -2407,16 +2551,38 @@ class RuntimeTemplate {
2407
2551
  `${importVar}_namespace_cache`
2408
2552
  )
2409
2553
  );
2554
+ const fakeMode = exportsType === "default-only" ? 0 : 2;
2555
+ const fakeArguments = fakeMode === 0 ? "" : ", 2";
2556
+ let fakeNamespace = `${RuntimeGlobals.createFakeNamespaceObject}(${importVar}${fakeArguments})`;
2557
+ if (synthesizesSpecNamespaceObject(originModule)) {
2558
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2559
+ runtimeRequirements.add(RuntimeGlobals.moduleCache);
2560
+ const owner = synthesizedNamespaceOwner(
2561
+ chunkGraph.getModuleId(module),
2562
+ fakeMode
2563
+ );
2564
+ fakeNamespace = `${RuntimeGlobals.specNamespaceObject}(${fakeNamespace}${owner})`;
2565
+ }
2410
2566
  return `/*#__PURE__*/ ${
2411
2567
  asiSafe ? "" : asiSafe === false ? ";" : "Object"
2412
- }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${
2413
- RuntimeGlobals.createFakeNamespaceObject
2414
- }(${importVar}${exportsType === "default-only" ? "" : ", 2"})))`;
2568
+ }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${fakeNamespace}))`;
2415
2569
  }
2416
2570
  }
2417
2571
 
2418
2572
  if (exportName.length > 0) {
2419
2573
  const exportsInfo = moduleGraph.getExportsInfo(module);
2574
+ // A name the module does not export is the namespace's to answer — reading
2575
+ // it is undefined and writing it fails — not the exports object's.
2576
+ if (
2577
+ !isModuleDeferred &&
2578
+ usesSpecNamespaceObject(module) &&
2579
+ exportsInfo.isExportProvided(exportName) === false
2580
+ ) {
2581
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2582
+ const ns = `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
2583
+
2584
+ return `${ns}${propertyAccess(exportName)}`;
2585
+ }
2420
2586
  // in some case the exported item is renamed (get this by getUsedName). for example,
2421
2587
  // x.default might be emitted as x.Z (default is renamed to Z)
2422
2588
  const used = exportsInfo.getUsedName(exportName, runtime);
@@ -2461,9 +2627,19 @@ class RuntimeTemplate {
2461
2627
  runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
2462
2628
  const id = chunkGraph.getModuleId(module);
2463
2629
  const type = getMakeDeferredNamespaceModeFromExportsType(exportsType);
2464
- const init = `${
2465
- RuntimeGlobals.makeDeferredNamespaceObject
2466
- }(${JSON.stringify(id)}, ${type})`;
2630
+ const names = getKnownExportNames(
2631
+ chunkGraph.moduleGraph,
2632
+ module,
2633
+ exportsType
2634
+ );
2635
+ runtimeRequirements.add(
2636
+ names
2637
+ ? RuntimeGlobals.hasSealedDeferredNamespace
2638
+ : RuntimeGlobals.hasSynthesizedDeferredNamespace
2639
+ );
2640
+ const init = `${RuntimeGlobals.makeDeferredNamespaceObject}(${JSON.stringify(
2641
+ id
2642
+ )}, ${type}${names ? `, ${JSON.stringify(names)}` : ""})`;
2467
2643
 
2468
2644
  return `/*#__PURE__*/ ${
2469
2645
  asiSafe ? "" : asiSafe === false ? ";" : "Object"
@@ -2490,6 +2666,16 @@ class RuntimeTemplate {
2490
2666
  // if we hit here, the importVar is either
2491
2667
  // - already a ES module namespace object
2492
2668
  // - or imported by a way that does not need interop.
2669
+ if (
2670
+ exportsType === "namespace" &&
2671
+ exportName.length === 0 &&
2672
+ usesSpecNamespaceObject(module)
2673
+ ) {
2674
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2675
+
2676
+ return `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
2677
+ }
2678
+
2493
2679
  return importVar;
2494
2680
  }
2495
2681
 
@@ -2570,7 +2756,7 @@ class RuntimeTemplate {
2570
2756
  * @param {string} options.message the message
2571
2757
  * @param {ChunkGraph} options.chunkGraph the chunk graph
2572
2758
  * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
2573
- * @param {Module=} options.originModule the module the `import()` is emitted into
2759
+ * @param {Module=} options.originModule the module the `import()` is emitted into, to report against
2574
2760
  * @returns {string} expression
2575
2761
  */
2576
2762
  blockPromise({
@@ -2600,156 +2786,32 @@ class RuntimeTemplate {
2600
2786
  message,
2601
2787
  chunkName: block.chunkName
2602
2788
  });
2603
- // `fetchPriority` is unsupported for ESM output (a native `import()` can't carry it,
2604
- // and the ESM chunk loader ignores the argument), so it never blocks the analyzable form.
2605
- // TODO recheck: browsers honor `fetchpriority` on `modulepreload` only when the
2606
- // preload scanner sees it, so a runtime-injected hint is inert; support it here if
2607
- // that changes.
2608
- const fetchPriority = chunkGroup.options.fetchPriority;
2609
- if (chunks.length === 1) {
2610
- const analyzable = this.analyzableChunkImport(
2611
- chunks[0],
2612
- comment,
2613
- runtimeRequirements,
2614
- originModule,
2615
- chunkGraph
2616
- );
2617
- if (analyzable !== null) {
2618
- return analyzable;
2619
- }
2620
- const chunkId = JSON.stringify(chunks[0].id);
2621
- runtimeRequirements.add(RuntimeGlobals.ensureChunk);
2622
-
2623
- if (fetchPriority) {
2624
- runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
2625
- }
2626
-
2627
- return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${
2628
- fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
2629
- })`;
2630
- } else if (chunks.length > 0) {
2631
- let needEnsureChunk = false;
2632
- /**
2633
- * Analyzable `import()` for a solely-owned JS chunk, else runtime ensureChunk.
2634
- * @param {Chunk} chunk chunk
2635
- * @returns {string} require chunk id code
2636
- */
2637
- const requireChunkId = (chunk) => {
2638
- const analyzable = this.analyzableChunkImport(
2639
- chunk,
2640
- "",
2641
- runtimeRequirements,
2642
- originModule,
2643
- chunkGraph
2644
- );
2645
- if (analyzable !== null) return analyzable;
2646
- needEnsureChunk = true;
2647
- return `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${
2648
- fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
2649
- })`;
2650
- };
2651
- const items = chunks.map(requireChunkId);
2652
- if (needEnsureChunk) {
2653
- runtimeRequirements.add(RuntimeGlobals.ensureChunk);
2654
- // Only needed when an `ensureChunk(id, priority)` call is actually emitted.
2655
- if (fetchPriority) {
2656
- runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
2657
- }
2658
- }
2659
- return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
2660
- }
2661
- return `Promise.resolve(${comment.trim()})`;
2662
- }
2663
-
2664
- /**
2665
- * Whether any module of `chunk` carries a source type with a chunk handler of its
2666
- * own, which `.ei` dispatches alongside the javascript one.
2667
- * @param {Chunk} chunk the chunk being imported
2668
- * @param {ChunkGraph} chunkGraph the chunk graph
2669
- * @returns {boolean} true when a handler beyond the javascript one is reached
2670
- */
2671
- _chunkLoadsBeyondJs(chunk, chunkGraph) {
2672
- for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
2673
- for (const type of chunkGraph.getModuleSourceTypes(module)) {
2674
- if (!TYPES_WITHOUT_CHUNK_HANDLER.has(type)) return true;
2789
+ // An output that cannot use a native `import()` gets no ESM chunk loader to ask,
2790
+ // so the reason is recorded here, where any build generates its imports.
2791
+ if (this.outputOptions.module && originModule !== undefined) {
2792
+ const outputReason = this._chunkImportOutputReason();
2793
+ if (outputReason !== null) {
2794
+ this._analyzableBailout(originModule, outputReason, false);
2675
2795
  }
2676
2796
  }
2677
- return false;
2678
- }
2679
-
2680
- /**
2681
- * For ESM module output, load a single statically-named chunk through the
2682
- * `analyzableChunkImport` helper — a literal `import("./chunk.js")` other bundlers
2683
- * and webpack itself can follow, wrapped to keep `ensureChunk` timing and deduplication.
2684
- * Returns `null` to fall back to the runtime `ensureChunk` form.
2685
- * @param {Chunk} chunk the chunk to load
2686
- * @param {string} comment leading comment (chunk name / message)
2687
- * @param {RuntimeRequirements} runtimeRequirements runtime requirements
2688
- * @param {Module | undefined} originModule the module the `import()` is emitted into
2689
- * @param {ChunkGraph} chunkGraph the chunk graph
2690
- * @returns {string | null} the import expression, or `null`
2691
- */
2692
- analyzableChunkImport(
2693
- chunk,
2694
- comment,
2695
- runtimeRequirements,
2696
- originModule,
2697
- chunkGraph
2698
- ) {
2699
- // `blockPromise` has already dropped any chunk without an id. Without an origin
2700
- // there is nothing the specifier could be relative to.
2701
- if (
2702
- !originModule ||
2703
- !this.supportsAnalyzable("import", chunkGraph, originModule)
2704
- ) {
2705
- return null;
2797
+ const fetchPriority = chunkGroup.options.fetchPriority;
2798
+ const priorityArg = fetchPriority
2799
+ ? `, ${JSON.stringify(fetchPriority)}`
2800
+ : "";
2801
+ if (chunks.length === 0) return `Promise.resolve(${comment.trim()})`;
2802
+ runtimeRequirements.add(RuntimeGlobals.ensureChunk);
2803
+ if (fetchPriority) {
2804
+ runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
2706
2805
  }
2707
- // `.ei` always performs the import, where `.e` only reaches the javascript
2708
- // loader when there is javascript to load. A module federation remote is the
2709
- // case that matters: its chunk is emitted by the container's build, not this one.
2710
- if (!JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) {
2711
- return this._analyzableBailout(
2712
- originModule,
2713
- "this compilation emits no javascript for the chunk, so there is nothing to import",
2714
- null
2715
- );
2806
+ if (chunks.length === 1) {
2807
+ const chunkId = JSON.stringify(chunks[0].id);
2808
+ return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${priorityArg})`;
2716
2809
  }
2717
- // Relative to the consuming chunk (`import.meta.url`) for `auto`, else an
2718
- // absolute publicPath prefix.
2719
- const specifier = this._getAnalyzableChunkSpecifier(
2720
- undefined,
2721
- chunk,
2722
- originModule,
2723
- chunkGraph
2810
+ const items = chunks.map(
2811
+ (chunk) =>
2812
+ `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${priorityArg})`
2724
2813
  );
2725
- if (specifier === null) {
2726
- return null;
2727
- }
2728
- // `import()` needs a resolvable specifier — relative (`./`, `../`), absolute (`/`)
2729
- // or a URL scheme. A bare one is a package name, so make it explicitly relative
2730
- // the way the chunk loader does. (`new URL(...)` callers accept bare vs their base.)
2731
- const resolvableSpecifier = /^"(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(
2732
- specifier
2733
- )
2734
- ? specifier
2735
- : `"./${specifier.slice(1)}`;
2736
- runtimeRequirements.add(RuntimeGlobals.analyzableChunkImport);
2737
- // Prefetch/preload children and every non-javascript source type are loaded by a
2738
- // `.f` handler, which `.ei` dispatches — but they attach to `.f`, so it has to
2739
- // exist. The runtime `ensureChunk` around it does not.
2740
- if (
2741
- chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
2742
- chunk.hasChildByOrder(chunkGraph, "preload", true) ||
2743
- chunk.hasChildByOrder(chunkGraph, "cssPreload", true) ||
2744
- this._chunkLoadsBeyondJs(chunk, chunkGraph)
2745
- ) {
2746
- runtimeRequirements.add(RuntimeGlobals.ensureChunkHandlers);
2747
- }
2748
- // Drop-in for `ensureChunk(id)`: the literal `import()` can be statically
2749
- // followed, the helper keeps webpack's install timing and deduplication.
2750
- return `${RuntimeGlobals.analyzableChunkImport}(${JSON.stringify(
2751
- chunk.id
2752
- )}, ${this.returningFunction(`import(${comment}${resolvableSpecifier})`)})`;
2814
+ return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
2753
2815
  }
2754
2816
 
2755
2817
  /**
@@ -2785,6 +2847,17 @@ class RuntimeTemplate {
2785
2847
  const late = this._settlesLate(chunk);
2786
2848
  if (late !== this._settlesLate(target)) return !late;
2787
2849
  }
2850
+ return this._hashRoundBefore(chunk, target);
2851
+ }
2852
+
2853
+ /**
2854
+ * Whether the four rounds alone settle `chunk` before `target`, leaving out what the
2855
+ * full-hash marks move: the order a runtime module generated in its chunk's round sees.
2856
+ * @param {Chunk} chunk the chunk whose hash would be read
2857
+ * @param {Chunk} target the chunk reading it
2858
+ * @returns {boolean} true when the hash exists by the time the target is hashed
2859
+ */
2860
+ _hashRoundBefore(chunk, target) {
2788
2861
  const chunkGraph = /** @type {ChunkGraph} */ (this.compilation.chunkGraph);
2789
2862
  const round = hashRound(chunk, chunkGraph);
2790
2863
  const targetRound = hashRound(target, chunkGraph);
@@ -2807,6 +2880,42 @@ class RuntimeTemplate {
2807
2880
  );
2808
2881
  }
2809
2882
 
2883
+ /**
2884
+ * Whether a `[chunkhash]`/`[contenthash]` name is settled before every chunk it is
2885
+ * written into, so a runtime module generated in its chunk's round can spell it.
2886
+ * @param {Chunk} chunk the chunk named
2887
+ * @param {string} template what names it
2888
+ * @param {Iterable<Chunk>} targets the chunks the name is written into
2889
+ * @returns {boolean} true when the hashes it reads exist by then
2890
+ */
2891
+ _hashedNameSettledBefore(chunk, template, targets) {
2892
+ const kinds = getTemplatedPathPlugin().getPresentKinds(template);
2893
+ // The compilation hash exists in no round a chunk is hashed in.
2894
+ if (kinds.has("fullhash") || kinds.has("hash")) return false;
2895
+ for (const target of targets) {
2896
+ if (!this._hashRoundBefore(chunk, target)) return false;
2897
+ }
2898
+ return true;
2899
+ }
2900
+
2901
+ /**
2902
+ * Whether the hashes a name reads are on the chunk now, which they are only once its
2903
+ * round of `createHash` has run — never while modules are being generated.
2904
+ * @param {Chunk} chunk the chunk named
2905
+ * @param {string} template what names it
2906
+ * @param {string} sourceType which asset of the chunk it names
2907
+ * @returns {boolean} true when the name can be resolved here
2908
+ */
2909
+ _hashedNamePresent(chunk, template, sourceType) {
2910
+ const kinds = getTemplatedPathPlugin().getPresentKinds(template);
2911
+ return (
2912
+ !kinds.has("fullhash") &&
2913
+ !kinds.has("hash") &&
2914
+ (!kinds.has("chunkhash") || chunk.hash !== undefined) &&
2915
+ (!kinds.has("contenthash") || chunk.contentHash[sourceType] !== undefined)
2916
+ );
2917
+ }
2918
+
2810
2919
  /**
2811
2920
  * Whether `createHash` settles this chunk's hash in the round that runs after the
2812
2921
  * compilation hash rather than in one of the four before it. Asked of the chunk
@@ -3068,35 +3177,6 @@ class RuntimeTemplate {
3068
3177
  this._chunksByIdForFold = undefined;
3069
3178
  }
3070
3179
 
3071
- /**
3072
- * Whether `chunk` can reach any of `targets` by following chunk groups, which is
3073
- * what turns a baked hashed name into a hash that depends on itself.
3074
- * @param {Chunk} chunk the referenced chunk
3075
- * @param {Iterable<Chunk>} targets the chunks the reference is written into
3076
- * @returns {boolean} true when one of them is reachable from `chunk`
3077
- */
3078
- _reachesAny(chunk, targets) {
3079
- const wanted = new Set(targets);
3080
- if (wanted.size === 0) return false;
3081
- if (wanted.has(chunk)) return true;
3082
- /** @type {Set<ChunkGroup>} */
3083
- const seen = new Set();
3084
- /** @type {ChunkGroup[]} */
3085
- const queue = [...chunk.groupsIterable];
3086
- for (const group of queue) seen.add(group);
3087
- for (let i = 0; i < queue.length; i++) {
3088
- for (const child of queue[i].childrenIterable) {
3089
- if (seen.has(child)) continue;
3090
- seen.add(child);
3091
- for (const candidate of child.chunks) {
3092
- if (wanted.has(candidate)) return true;
3093
- }
3094
- queue.push(child);
3095
- }
3096
- }
3097
- return false;
3098
- }
3099
-
3100
3180
  /**
3101
3181
  * The chunks a reference emitted into `module` is written into — the assets a
3102
3182
  * stand-in of ours would land in, and so the only ones a deferred fill could go
@@ -3212,7 +3292,7 @@ class RuntimeTemplate {
3212
3292
  * The `../` path from a chunk's own asset back to the output root. Hashes are
3213
3293
  * neutralized first: a runtime module is generated once to be hashed, before any
3214
3294
  * hash exists, so resolving one there throws — and `RuntimeModule.updateHash`
3215
- * swallows that, pinning the module's hash to the message.
3295
+ * lets that throw fail the build rather than hashing it.
3216
3296
  * @param {Chunk} chunk the chunk whose asset holds the reference
3217
3297
  * @param {boolean} enforceRelative whether the answer keeps a leading `./`
3218
3298
  * @returns {string} the path back to the output root
@@ -3243,7 +3323,10 @@ class RuntimeTemplate {
3243
3323
  * @returns {Placement} where a literal in it is read from
3244
3324
  */
3245
3325
  _modulePlacement(module, chunkGraph) {
3246
- return this._placementOf(this._moduleChunks(module, chunkGraph));
3326
+ return this._placementOf(
3327
+ this._moduleChunks(module, chunkGraph),
3328
+ isHotModule(module)
3329
+ );
3247
3330
  }
3248
3331
 
3249
3332
  /**
@@ -3262,11 +3345,12 @@ class RuntimeTemplate {
3262
3345
 
3263
3346
  /**
3264
3347
  * The one answer every chunk in `chunks` agrees on, with either half `null` where
3265
- * they do not.
3348
+ * they do not — under HMR the update chunk, which re-runs the module, has a say too.
3266
3349
  * @param {Iterable<Chunk>} chunks the chunks a literal is written into
3350
+ * @param {boolean=} hot whether a hot update can re-run what is written
3267
3351
  * @returns {Placement} where a literal in them is read from
3268
3352
  */
3269
- _placementOf(chunks) {
3353
+ _placementOf(chunks, hot = false) {
3270
3354
  /** @type {Placement | undefined} */
3271
3355
  let first;
3272
3356
  /** @type {string | null} */
@@ -3275,13 +3359,17 @@ class RuntimeTemplate {
3275
3359
  let loaded = null;
3276
3360
  for (const chunk of chunks) {
3277
3361
  const own = this._chunkPlacement(chunk);
3362
+ const ownUndo =
3363
+ hot && own.undo !== null && own.undo !== this._hotUpdateUndo(chunk)
3364
+ ? null
3365
+ : own.undo;
3278
3366
  if (first === undefined) {
3279
3367
  first = own;
3280
- undo = own.undo;
3368
+ undo = ownUndo;
3281
3369
  loaded = own.loaded;
3282
3370
  continue;
3283
3371
  }
3284
- if (undo !== own.undo) undo = null;
3372
+ if (undo !== ownUndo) undo = null;
3285
3373
  if (loaded !== own.loaded) loaded = null;
3286
3374
  }
3287
3375
  if (first === undefined) return NO_PLACEMENT;
@@ -3301,16 +3389,9 @@ class RuntimeTemplate {
3301
3389
  * @param {Chunk} chunk the worker's entry chunk
3302
3390
  * @param {Module} module the module the reference is emitted into
3303
3391
  * @param {ChunkGraph} chunkGraph the chunk graph
3304
- * @param {RuntimeRequirements} runtimeRequirements what the consuming chunk needs
3305
3392
  * @returns {string | null} a quoted literal, or `null` to fall back
3306
3393
  */
3307
- getAnalyzableWorkerUrl(
3308
- overridePublicPath,
3309
- chunk,
3310
- module,
3311
- chunkGraph,
3312
- runtimeRequirements
3313
- ) {
3394
+ getAnalyzableWorkerUrl(overridePublicPath, chunk, module, chunkGraph) {
3314
3395
  // Without an id nothing can name the chunk in a stand-in.
3315
3396
  if (
3316
3397
  chunk.id === null ||
@@ -3322,8 +3403,7 @@ class RuntimeTemplate {
3322
3403
  overridePublicPath,
3323
3404
  chunk,
3324
3405
  module,
3325
- chunkGraph,
3326
- runtimeRequirements
3406
+ chunkGraph
3327
3407
  );
3328
3408
  }
3329
3409
 
@@ -3336,12 +3416,11 @@ class RuntimeTemplate {
3336
3416
  * @param {Module | undefined} consumingModule the module the reference is emitted
3337
3417
  * into, or `undefined` when `consumingChunks` names where it goes instead
3338
3418
  * @param {ChunkGraph} chunkGraph the chunk graph
3339
- * @param {RuntimeRequirements=} runtimeRequirements set when the caller wraps the result in
3340
- * `new URL(...)` and so accepts a runtime public path prefix around the literal filename
3341
3419
  * @param {Chunk[]=} consumingChunks the chunks the reference is written into, where
3342
3420
  * they are known without a module to read them from
3343
3421
  * @param {string=} sourceType which half of the chunk is named — its javascript by
3344
3422
  * default, or its stylesheet
3423
+ * @param {boolean=} hot whether a hot update can re-run what is written
3345
3424
  * @returns {string | null} a JS string literal or expression, or `null` to fall back to the runtime form
3346
3425
  */
3347
3426
  _getAnalyzableChunkSpecifier(
@@ -3349,20 +3428,16 @@ class RuntimeTemplate {
3349
3428
  chunk,
3350
3429
  consumingModule,
3351
3430
  chunkGraph,
3352
- runtimeRequirements,
3353
3431
  consumingChunks,
3354
- sourceType = JAVASCRIPT_TYPE
3432
+ sourceType = JAVASCRIPT_TYPE,
3433
+ hot = isHotModule(consumingModule)
3355
3434
  ) {
3356
3435
  const { compilation } = this;
3357
3436
  const { outputOptions } = compilation;
3358
3437
  const naming = CHUNK_ASSET_NAMING.get(sourceType);
3359
3438
  // Nothing here names this type's asset, so nothing can spell where it will be.
3360
3439
  if (naming === undefined) return null;
3361
- const template = this._resolveChunkFilenameTemplate(
3362
- naming.template(chunk, outputOptions),
3363
- chunk,
3364
- sourceType
3365
- );
3440
+ const template = this._chunkAssetTemplate(chunk, sourceType);
3366
3441
  if (template === null) return null;
3367
3442
  // A hashed name is settled long after this code is generated, so a stand-in is
3368
3443
  // emitted and filled in once the hash exists.
@@ -3374,92 +3449,93 @@ class RuntimeTemplate {
3374
3449
  const chunks =
3375
3450
  consumingChunks ||
3376
3451
  this._moduleChunks(/** @type {Module} */ (consumingModule), chunkGraph);
3377
- const namesFirst = this._namesBeforeAll(chunk, chunks);
3378
- // An id names the chunk in the stand-in. No reference reaches here without one —
3379
- // `blockPromise` drops an id-less chunk before asking, and one the whole build
3380
- // keeps has no name to be emitted under — so the guard carries no reason of its
3381
- // own; it only keeps `null` out of a name. A pair naming each other is fine here:
3382
- // `RealContentHashPlugin`, which deferring requires, re-hashes the pair as one
3383
- // group, so neither hash chases the other.
3384
- const canReserve =
3385
- chunk.id !== null && this._canDeferAnalyzableName(chunks);
3386
- // A content-named consumer bakes anyway when this chunk settles first: the fold
3387
- // puts the name into its hash. Only what `_foldsWholeName` covers, though — and
3388
- // a pair that reaches back has no fold order, so only the one hashing first does.
3389
- const canFold = !canReserve && namesFirst;
3390
- /**
3391
- * @returns {null} always, having recorded why no stand-in may be reserved
3392
- */
3393
- const cannotReserve = () =>
3394
- this._analyzableBailout(
3395
- consumingModule,
3396
- !namesFirst && this._reachesAny(chunk, chunks)
3397
- ? "this chunk and the one it references name each other, which only optimization.realContentHash could settle"
3398
- : DEFER_BAILOUT,
3399
- null
3400
- );
3401
- if (deferred && !canReserve && !canFold) return cannotReserve();
3402
- const filename = deferred
3403
- ? ""
3404
- : compilation.getPath(/** @type {string} */ (template), {
3405
- chunk,
3406
- // Matches what names the asset, or a placeholder resolved here would
3407
- // not be the one on disk.
3408
- runtime: chunk.runtime,
3409
- contentHashType: sourceType
3410
- });
3452
+ // An id names the chunk in the stand-in; `blockPromise` drops an id-less chunk
3453
+ // before asking, so the guard only keeps `null` out of a name.
3454
+ if (chunk.id === null) return null;
3455
+ // A runtime module is generated in its chunk's round of `createHash`, where a
3456
+ // hashed name settled earlier exists: spelled, so a hot update carries the new one.
3457
+ const settled =
3458
+ deferred &&
3459
+ template !== undefined &&
3460
+ this._hashedNamePresent(chunk, template, sourceType) &&
3461
+ this._namesBeforeAll(chunk, chunks);
3462
+ const canReserve = this._canDeferAnalyzableName(chunks);
3463
+ // A content-named consumer folds this name into its hash when it settles first;
3464
+ // what the fold cannot cover is repaired instead.
3465
+ const canFold = !canReserve && this._namesBeforeAll(chunk, chunks);
3466
+ const filename =
3467
+ deferred && !settled
3468
+ ? ""
3469
+ : compilation.getPath(/** @type {string} */ (template), {
3470
+ chunk,
3471
+ // Matches what names the asset, or a placeholder resolved here would
3472
+ // not be the one on disk.
3473
+ runtime: chunk.runtime,
3474
+ contentHashType: sourceType
3475
+ });
3411
3476
  /**
3412
3477
  * @param {SpecifierPart[]} prefix what goes in front of the chunk's filename
3413
- * @returns {string | null} the specifier already quoted, or `null` when the
3414
- * recipe needs a stand-in that cannot be reserved
3478
+ * @returns {string} the specifier already quoted
3415
3479
  */
3416
3480
  const specifier = (prefix) => {
3417
- if (!deferred) {
3481
+ if (!deferred || settled) {
3418
3482
  const text = literalText(prefix);
3419
3483
  if (text !== null) return toJsStringLiteral(text + filename);
3420
3484
  }
3421
- if (!canReserve && !(canFold && this._foldsWholeName(prefix, chunks))) {
3422
- return cannotReserve();
3423
- }
3485
+ const repair =
3486
+ !canReserve && !(canFold && this._foldsWholeName(prefix, chunks));
3424
3487
  return toJsStringLiteral(
3425
- this._reserveAnalyzableSpecifier([
3426
- ...prefix,
3427
- [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
3428
- ])
3488
+ this._reserveAnalyzableSpecifier(
3489
+ this._markedForRepair(repair, [
3490
+ ...prefix,
3491
+ // A settled name is carried as text: the fill would spell the same,
3492
+ // but only text of its own moves the runtime module's hash.
3493
+ settled
3494
+ ? ["literal", filename]
3495
+ : [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
3496
+ ])
3497
+ )
3429
3498
  );
3430
3499
  };
3431
3500
  if (overridePublicPath) {
3432
- const resolved = this._resolvePublicPathPrefix(
3433
- overridePublicPath,
3434
- consumingModule,
3435
- chunks
3436
- );
3501
+ const resolved = this._resolvePublicPathPrefix(overridePublicPath);
3437
3502
  return resolved === null ? null : specifier(resolved);
3438
3503
  }
3439
3504
  const { publicPath } = outputOptions;
3440
3505
  if (publicPath === "auto") {
3441
- const { undo } = this._placementOf(chunks);
3506
+ const { undo } = this._placementOf(chunks, hot);
3442
3507
  if (undo !== null) return specifier([["literal", undo]]);
3443
3508
  // Different depths — no one `../` path is right for every asset the reference
3444
3509
  // lands in, so the deferred pass builds each asset's own.
3445
- const perAsset = specifier([["undo", ""]]);
3446
- if (perAsset !== null) return perAsset;
3447
- // Only a stand-in that could not be reserved reaches here, and `specifier`
3448
- // has already recorded why.
3449
- if (deferred || !runtimeRequirements) return null;
3450
- // No bundler follows a concatenation, but a `new URL(...)` caller still sheds
3451
- // the `.u(id)` lookup this way; `import()` needs a static specifier.
3452
- runtimeRequirements.add(RuntimeGlobals.publicPath);
3453
- return `${RuntimeGlobals.publicPath} + ${toJsStringLiteral(filename)}`;
3510
+ return specifier([["undo", ""]]);
3454
3511
  }
3455
3512
  const prefix = this._analyzablePathPrefix(
3456
3513
  consumingModule,
3457
3514
  chunkGraph,
3458
- chunks
3515
+ chunks,
3516
+ undefined,
3517
+ hot
3459
3518
  );
3460
3519
  return prefix === null ? null : specifier(prefix);
3461
3520
  }
3462
3521
 
3522
+ /**
3523
+ * The template this chunk's asset of `sourceType` is named by: `undefined` where a
3524
+ * function reads a hash, `null` where nothing here names that type or it answers nothing.
3525
+ * @param {Chunk} chunk the chunk
3526
+ * @param {string} sourceType which asset of the chunk
3527
+ * @returns {string | undefined | null} the template
3528
+ */
3529
+ _chunkAssetTemplate(chunk, sourceType) {
3530
+ const naming = CHUNK_ASSET_NAMING.get(sourceType);
3531
+ if (naming === undefined) return null;
3532
+ return this._resolveChunkFilenameTemplate(
3533
+ naming.template(chunk, this.outputOptions),
3534
+ chunk,
3535
+ sourceType
3536
+ );
3537
+ }
3538
+
3463
3539
  /**
3464
3540
  * The parts that go in front of a name so a literal read from the chunk holding it
3465
3541
  * reaches what the runtime would. A public path needing no base is the whole answer.
@@ -3473,18 +3549,24 @@ class RuntimeTemplate {
3473
3549
  * @param {ChunkGraph} chunkGraph the chunk graph
3474
3550
  * @param {Iterable<Chunk>} chunks the chunks a stand-in would be written into
3475
3551
  * @param {string=} relativeBase an entry `baseUri` read against the output root
3552
+ * @param {boolean=} hot whether a hot update can re-run what is written
3476
3553
  * @returns {SpecifierPart[] | null} the parts, or `null` having recorded why not
3477
3554
  */
3478
- _analyzablePathPrefix(module, chunkGraph, chunks, relativeBase) {
3555
+ _analyzablePathPrefix(
3556
+ module,
3557
+ chunkGraph,
3558
+ chunks,
3559
+ relativeBase,
3560
+ hot = isHotModule(module)
3561
+ ) {
3479
3562
  const publicPath = /** @type {PublicPath} */ (
3480
3563
  this.outputOptions.publicPath
3481
3564
  );
3482
3565
  const shape = this._publicPathShape();
3483
3566
  if (shape === undefined) return null;
3484
- const resolve = () =>
3485
- this._resolvePublicPathPrefix(publicPath, module, chunks);
3567
+ const resolve = () => this._resolvePublicPathPrefix(publicPath);
3486
3568
  if (isBaseIndependent(shape)) return resolve();
3487
- const { undo, loaded } = this._placementOf(chunks);
3569
+ const { undo, loaded } = this._placementOf(chunks, hot);
3488
3570
  // What a chunk the loader fetched climbs back out of. One of no depth leaves
3489
3571
  // nothing to climb, and then both answers put the same text in front.
3490
3572
  const served = this._publicPathClimb();
@@ -3518,12 +3600,9 @@ class RuntimeTemplate {
3518
3600
  * the deferred pass whole instead. A function is called for its value rather than
3519
3601
  * read as a template, so one whose answer moves with the hash is called again there.
3520
3602
  * @param {PublicPath} publicPath the configured public path
3521
- * @param {Module=} module the module the reference is emitted into, to record why
3522
- * a name no stand-in may be reserved for kept the runtime form
3523
- * @param {Iterable<Chunk>=} chunks the chunks a stand-in would be written into
3524
3603
  * @returns {SpecifierPart[] | null} the parts, or `null` when it cannot be known
3525
3604
  */
3526
- _resolvePublicPathPrefix(publicPath, module, chunks) {
3605
+ _resolvePublicPathPrefix(publicPath) {
3527
3606
  if (typeof publicPath === "function") {
3528
3607
  // One that answers nothing to a probe cannot be placed, absolute or not.
3529
3608
  if (this._publicPathShape() === undefined) return null;
@@ -3534,28 +3613,18 @@ class RuntimeTemplate {
3534
3613
  if (resolved !== null) return [["literal", resolved]];
3535
3614
  // Called again by the fill against the compilation hash, so what it answers
3536
3615
  // there is that hash by another name.
3537
- return this._canDeferOrBakeFullHash(true, chunks, module)
3538
- ? [["publicPath", ""]]
3539
- : null;
3616
+ return [["publicPath", ""]];
3540
3617
  }
3541
3618
  if (!publicPath.includes("[")) return [["literal", publicPath]];
3542
3619
  // A re-encoded digest cannot be spelled by a stand-in, so it stays a template.
3543
3620
  if (getTemplatedPathPlugin().usesFullHashDigest(publicPath)) {
3544
- return this._canDeferOrBakeFullHash(true, chunks, module)
3545
- ? [["template", publicPath]]
3546
- : null;
3621
+ return [["template", publicPath]];
3547
3622
  }
3548
3623
  const literal = this.compilation.getPath(
3549
3624
  publicPath,
3550
3625
  this._deferredFullHashPathData()
3551
3626
  );
3552
- return this._canDeferOrBakeFullHash(
3553
- this._hasReservedFullHash(literal),
3554
- chunks,
3555
- module
3556
- )
3557
- ? [["literal", literal]]
3558
- : null;
3627
+ return [["literal", literal]];
3559
3628
  }
3560
3629
 
3561
3630
  /**
@@ -3640,7 +3709,7 @@ class RuntimeTemplate {
3640
3709
  relativeBase
3641
3710
  );
3642
3711
  if (prefix === null) return null;
3643
- return this._specifierOf([...prefix, ...file], chunks, module);
3712
+ return this._specifierOf([...prefix, ...file], chunks);
3644
3713
  }
3645
3714
  // No public path to place it against, so the `../` path back to the output root
3646
3715
  // is the whole prefix. Different depths — no one is right for every asset the
@@ -3650,23 +3719,22 @@ class RuntimeTemplate {
3650
3719
  const parts = [undo === null ? ["undo", ""] : ["literal", undo]];
3651
3720
  if (relativeBase !== undefined) parts.push(["literal", relativeBase]);
3652
3721
  parts.push(...file);
3653
- return this._specifierOf(parts, chunks, module);
3722
+ return this._specifierOf(parts, chunks);
3654
3723
  }
3655
3724
 
3656
3725
  /**
3657
3726
  * Static `new URL(<file>, import.meta.url)` for every stylesheet a runtime can load,
3658
- * keyed by chunk id — one that cannot be named leaves the map incomplete, and its
3659
- * id keeps the runtime `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
3727
+ * keyed by chunk id, or `null` when they have to keep the runtime
3728
+ * `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
3660
3729
  * and the plugin declaring what it needs ask this, so the two always agree. The
3661
3730
  * runtime hands an absolute url string to `link.href`, and so does this — the browser
3662
3731
  * resolves the element against the document, which is not where the chunk sits, and
3663
- * the loader reads the url as text either way. Nothing is written out for a runtime
3664
- * that also carries the hot handler; see below.
3732
+ * the loader reads the url as text either way.
3665
3733
  * @param {Chunk} runtimeChunk the chunk holding the stylesheet loader
3666
3734
  * @param {ChunkGraph} chunkGraph the chunk graph
3667
3735
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3668
3736
  * @param {Module=} consumingModule the runtime module, where one exists to report against
3669
- * @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
3737
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3670
3738
  */
3671
3739
  analyzableCssChunkUrls(
3672
3740
  runtimeChunk,
@@ -3698,14 +3766,14 @@ class RuntimeTemplate {
3698
3766
  /**
3699
3767
  * Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
3700
3768
  * runtime can hint at with `<link rel="prefetch"/"modulepreload">`, keyed by chunk
3701
- * id — one that cannot be named leaves the map incomplete, and its id keeps the
3702
- * runtime `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
3769
+ * id, or `null` when they have to keep the runtime
3770
+ * `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
3703
3771
  * them and the plugin declaring what it needs ask this, so the two always agree.
3704
3772
  * @param {Chunk} runtimeChunk the chunk holding the hint handlers
3705
3773
  * @param {ChunkGraph} chunkGraph the chunk graph
3706
3774
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3707
3775
  * @param {Module=} consumingModule the runtime module, where one exists to report against
3708
- * @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
3776
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3709
3777
  */
3710
3778
  analyzableChunkScriptUrls(
3711
3779
  runtimeChunk,
@@ -3742,17 +3810,156 @@ class RuntimeTemplate {
3742
3810
  );
3743
3811
  }
3744
3812
 
3813
+ /**
3814
+ * Why no chunk import of this build can be a native `import()`, read from the
3815
+ * output configuration alone, or `null` when nothing in it rules one out.
3816
+ * @returns {string | null} the reason
3817
+ */
3818
+ _chunkImportOutputReason() {
3819
+ const { chunkFormat, importFunctionName } = this.outputOptions;
3820
+ if (chunkFormat !== "module") {
3821
+ return `output.chunkFormat is ${JSON.stringify(chunkFormat)}, so chunks are not read through a native import()`;
3822
+ }
3823
+ if (importFunctionName !== "import") {
3824
+ return `output.importFunctionName is ${JSON.stringify(importFunctionName)}, so the call site is not a native import()`;
3825
+ }
3826
+ return null;
3827
+ }
3828
+
3829
+ /**
3830
+ * Records that this runtime reads its chunks some way other than a native
3831
+ * `import()`, so no literal can name what it loads. Recorded on the entries that
3832
+ * chose it, which is where the setting behind it lives.
3833
+ * @param {Chunk} chunk the runtime chunk
3834
+ * @param {ChunkGraph} chunkGraph the chunk graph
3835
+ * @returns {void}
3836
+ */
3837
+ reportChunkImportBailout(chunk, chunkGraph) {
3838
+ if (!this.outputOptions.module) return;
3839
+ const entryOptions = chunk.getEntryOptions();
3840
+ const chunkLoading =
3841
+ entryOptions && entryOptions.chunkLoading !== undefined
3842
+ ? entryOptions.chunkLoading
3843
+ : this.outputOptions.chunkLoading;
3844
+ if (chunkLoading === "import") return;
3845
+ const subject = entryOptions && entryOptions.worker ? "worker" : "runtime";
3846
+ const reason = `this ${subject} loads its chunks with ${JSON.stringify(chunkLoading)}, not "import"`;
3847
+ for (const module of chunkGraph.getChunkEntryModulesIterable(chunk)) {
3848
+ this._analyzableBailout(module, reason, false);
3849
+ }
3850
+ }
3851
+
3852
+ /**
3853
+ * The chunks this loader can be handed an id for: the ones held by a group outside
3854
+ * the initial wave, which is what an `import()` or a context map turns into an id.
3855
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3856
+ * @returns {Set<Chunk>} the chunks reachable from here through a non-initial group
3857
+ */
3858
+ _loadableChunks(runtimeChunk) {
3859
+ const queue = new Set(runtimeChunk.groupsIterable);
3860
+ /** @type {Set<Chunk>} */
3861
+ const chunks = new Set();
3862
+ for (const group of queue) {
3863
+ if (!group.isInitial()) {
3864
+ for (const chunk of group.chunks) chunks.add(chunk);
3865
+ }
3866
+ for (const child of group.childrenIterable) queue.add(child);
3867
+ }
3868
+ return chunks;
3869
+ }
3870
+
3871
+ /**
3872
+ * Whether the loader still needs to build a url from a chunk id, which is the case
3873
+ * for a chunk it can be asked for that `analyzableChunkImports` leaves unnamed: one
3874
+ * carrying a runtime of its own, or one a second entrypoint has at startup.
3875
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3876
+ * @param {ChunkGraph} chunkGraph the chunk graph
3877
+ * @returns {boolean} true when an id the map does not hold can reach the loader
3878
+ */
3879
+ chunkImportsNeedRuntimeUrl(runtimeChunk, chunkGraph) {
3880
+ const installed = new Set(runtimeChunk.getAllInitialChunks());
3881
+ for (const chunk of this._loadableChunks(runtimeChunk)) {
3882
+ if (chunk === runtimeChunk) continue;
3883
+ if (!chunk.hasRuntime() && !installed.has(chunk)) continue;
3884
+ if (JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) return true;
3885
+ }
3886
+ return false;
3887
+ }
3888
+
3889
+ /**
3890
+ * A literal `import()` specifier for every javascript chunk a runtime loads on
3891
+ * demand, keyed by chunk id, or `null` when one of them cannot be named here. The
3892
+ * map is written into the runtime chunk rather than at each import site, so a
3893
+ * hashed chunk name reaches no module that imports it.
3894
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3895
+ * @param {ChunkGraph} chunkGraph the chunk graph
3896
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3897
+ * @param {Module=} consumingModule the runtime module, where one exists to report against
3898
+ * @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
3899
+ */
3900
+ analyzableChunkImports(
3901
+ runtimeChunk,
3902
+ chunkGraph,
3903
+ runtimeRequirements,
3904
+ consumingModule
3905
+ ) {
3906
+ // The runtime names the scope `__webpack_public_path__` belongs to, so the
3907
+ // answer holds whether or not a runtime module is there to ask about.
3908
+ if (
3909
+ !this.supportsAnalyzable(
3910
+ "import",
3911
+ chunkGraph,
3912
+ consumingModule,
3913
+ runtimeChunk.runtime
3914
+ )
3915
+ ) {
3916
+ return null;
3917
+ }
3918
+ // An initial chunk and one carrying a runtime are both reached by a static
3919
+ // import, so naming either here would only make two hashes chase each other.
3920
+ const installed = new Set(runtimeChunk.getAllInitialChunks());
3921
+ /** @type {Chunk[]} */
3922
+ const chunks = [];
3923
+ for (const chunk of runtimeChunk.getAllReferencedChunks()) {
3924
+ if (
3925
+ chunk === runtimeChunk ||
3926
+ chunk.hasRuntime() ||
3927
+ installed.has(chunk) ||
3928
+ !JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)
3929
+ ) {
3930
+ continue;
3931
+ }
3932
+ chunks.push(chunk);
3933
+ }
3934
+ const specifiers = this._analyzableChunkSpecifiers(
3935
+ chunks,
3936
+ chunkGraph,
3937
+ consumingModule,
3938
+ [runtimeChunk],
3939
+ JAVASCRIPT_TYPE,
3940
+ runtimeRequirements
3941
+ );
3942
+ if (specifiers === null) return null;
3943
+ for (const [id, specifier] of specifiers) {
3944
+ // A bare specifier is a package name, so spell it relative the way the
3945
+ // runtime form's `.p + <file>` would have resolved it.
3946
+ if (!RESOLVABLE_SPECIFIER_REGEXP.test(specifier.slice(1))) {
3947
+ specifiers.set(id, `"./${specifier.slice(1)}`);
3948
+ }
3949
+ }
3950
+ return specifiers;
3951
+ }
3952
+
3745
3953
  /**
3746
3954
  * The urls of one asset of each of `chunks`, written out so they can be read by
3747
- * chunk id. A chunk that cannot be named here leaves the map incomplete rather
3748
- * than losing it — the consumer keeps the runtime form for the ids the map lacks.
3955
+ * chunk id, or `null` as soon as one of them cannot be named here.
3749
3956
  * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
3750
3957
  * @param {ChunkGraph} chunkGraph the chunk graph
3751
3958
  * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
3752
3959
  * @param {Chunk[]} consumingChunks the chunks the urls are written into
3753
3960
  * @param {string} sourceType which asset of each chunk to name
3754
3961
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
3755
- * @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
3962
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3756
3963
  */
3757
3964
  _analyzableChunkUrls(
3758
3965
  chunks,
@@ -3762,17 +3969,51 @@ class RuntimeTemplate {
3762
3969
  sourceType,
3763
3970
  runtimeRequirements
3764
3971
  ) {
3765
- // A map written now cannot answer for whatever id an update names, so it yields
3766
- // to HMR — analyzable output is what ships.
3767
- if (
3768
- runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers) ||
3769
- !this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)
3770
- ) {
3972
+ if (!this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)) {
3771
3973
  return null;
3772
3974
  }
3975
+ const urls = this._analyzableChunkSpecifiers(
3976
+ chunks,
3977
+ chunkGraph,
3978
+ consumingModule,
3979
+ consumingChunks,
3980
+ sourceType,
3981
+ runtimeRequirements
3982
+ );
3983
+ if (urls === null) return null;
3984
+ for (const [id, specifier] of urls) {
3985
+ urls.set(id, `${this.importMetaUrl(specifier)}.href`);
3986
+ }
3987
+ return urls;
3988
+ }
3989
+
3990
+ /**
3991
+ * The quoted specifier naming one asset of each of `chunks`, keyed by chunk id, or
3992
+ * `null` as soon as one of them cannot be named here. What the name is read against
3993
+ * is the caller's: a url resolves it, an `import()` hands it to the loader.
3994
+ * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
3995
+ * @param {ChunkGraph} chunkGraph the chunk graph
3996
+ * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
3997
+ * @param {Chunk[]} consumingChunks the chunks the specifiers are written into
3998
+ * @param {string} sourceType which asset of each chunk to name
3999
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
4000
+ * @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
4001
+ */
4002
+ _analyzableChunkSpecifiers(
4003
+ chunks,
4004
+ chunkGraph,
4005
+ consumingModule,
4006
+ consumingChunks,
4007
+ sourceType,
4008
+ runtimeRequirements
4009
+ ) {
4010
+ // A hot update re-ships the runtime module only when its own code changes, so
4011
+ // each name has to be text nothing but an id joining or leaving the map can move.
4012
+ const hot = runtimeRequirements.has(
4013
+ RuntimeGlobals.hmrDownloadUpdateHandlers
4014
+ );
3773
4015
  /** @type {Map<ChunkId, string>} */
3774
- const urls = new Map();
3775
- let complete = true;
4016
+ const specifiers = new Map();
3776
4017
  for (const chunk of chunks) {
3777
4018
  if (chunk.id === null) continue;
3778
4019
  const specifier = this._getAnalyzableChunkSpecifier(
@@ -3780,18 +4021,74 @@ class RuntimeTemplate {
3780
4021
  chunk,
3781
4022
  consumingModule,
3782
4023
  chunkGraph,
3783
- undefined,
3784
4024
  consumingChunks,
3785
- sourceType
4025
+ sourceType,
4026
+ hot
3786
4027
  );
3787
- // `_getAnalyzableChunkSpecifier` has already recorded why.
3788
- if (specifier === null) {
3789
- complete = false;
4028
+ if (specifier === null) return null;
4029
+ if (
4030
+ hot &&
4031
+ !this._settledUnderHot(specifier, chunk, sourceType, consumingChunks)
4032
+ ) {
4033
+ return this._analyzableBailout(consumingModule, HOT_NAME_BAILOUT, null);
4034
+ }
4035
+ specifiers.set(chunk.id, specifier);
4036
+ }
4037
+ return specifiers.size > 0 ? specifiers : null;
4038
+ }
4039
+
4040
+ /**
4041
+ * Whether a url a hot update re-ships moves only with the runtime module's own text:
4042
+ * spelled here, or a stand-in of each asset's depth and a hash-free or settled name.
4043
+ * @param {string} specifier the specifier already quoted
4044
+ * @param {Chunk} chunk the chunk it names
4045
+ * @param {string} sourceType which asset of the chunk it names
4046
+ * @param {Chunk[]} consumingChunks the chunks the map is written into
4047
+ * @returns {boolean} true when no update moves what the fill spells
4048
+ */
4049
+ _settledUnderHot(specifier, chunk, sourceType, consumingChunks) {
4050
+ const match = ANALYZABLE_TOKEN_PAYLOAD.exec(specifier);
4051
+ if (match === null) return true;
4052
+ const parts = RuntimeTemplate._readAnalyzableSpecifier(match[1]);
4053
+ if (parts === null) return false;
4054
+ for (const [kind, value] of parts) {
4055
+ if (kind === "undo") continue;
4056
+ if (kind === "literal" && !this._hasReservedFullHash(String(value))) {
3790
4057
  continue;
3791
4058
  }
3792
- urls.set(chunk.id, `${this.importMetaUrl(specifier)}.href`);
4059
+ if (!CHUNK_SPECIFIER_PART_KINDS.has(kind)) return false;
3793
4060
  }
3794
- return urls.size > 0 ? { urls, complete } : null;
4061
+ const template = this._chunkAssetTemplate(chunk, sourceType);
4062
+ return (
4063
+ typeof template === "string" &&
4064
+ (!HASH_IN_FILENAME.test(template) ||
4065
+ this._hashedNameSettledBefore(chunk, template, consumingChunks))
4066
+ );
4067
+ }
4068
+
4069
+ /**
4070
+ * The `../` path from a chunk's hot update file, which re-runs its modules, back to
4071
+ * the output root. Hashes are neutralized; the chunk's own id may add a directory.
4072
+ * @param {Chunk} chunk the chunk being updated
4073
+ * @returns {string} the path back to the output root
4074
+ */
4075
+ _hotUpdateUndo(chunk) {
4076
+ const cached = this._hotUpdateUndoByChunk.get(chunk);
4077
+ if (cached !== undefined) return cached;
4078
+ const { outputOptions } = this;
4079
+ if (this._hotUpdateShapeText === undefined) {
4080
+ this._hotUpdateShapeText = outputOptions.hotUpdateChunkFilename.replace(
4081
+ HASH_IN_FILENAME_GLOBAL,
4082
+ "x"
4083
+ );
4084
+ }
4085
+ const undo = getUndoPath(
4086
+ this.compilation.getPath(this._hotUpdateShapeText, { chunk }),
4087
+ /** @type {string} */ (outputOptions.path),
4088
+ true
4089
+ );
4090
+ this._hotUpdateUndoByChunk.set(chunk, undo);
4091
+ return undo;
3795
4092
  }
3796
4093
 
3797
4094
  /**
@@ -3997,7 +4294,7 @@ class RuntimeTemplate {
3997
4294
  * @returns {string} the stand-in to emit
3998
4295
  */
3999
4296
  _reserveAnalyzableSpecifier(parts) {
4000
- return `./@@webpackAnalyzableChunk:${Buffer.from(JSON.stringify(parts))
4297
+ return `${ANALYZABLE_TOKEN_PREFIX}${Buffer.from(JSON.stringify(parts))
4001
4298
  .toString("base64")
4002
4299
  .replace(/\+/g, "-")
4003
4300
  .replace(/\//g, "_")
@@ -4068,6 +4365,10 @@ class RuntimeTemplate {
4068
4365
  async () => {
4069
4366
  const { outputOptions } = compilation;
4070
4367
  const fullHash = compilation.hash;
4368
+ // The assets a stand-in landed in whose hashed name has to be brought
4369
+ // back in line, which `RealContentHashPlugin` then does.
4370
+ /** @type {Set<string>} */
4371
+ const repairedAssets = new Set();
4071
4372
  /** @type {Map<string, Chunk> | undefined} */
4072
4373
  let chunksById;
4073
4374
  /** @type {Map<string, Chunk> | undefined} */
@@ -4122,7 +4423,9 @@ class RuntimeTemplate {
4122
4423
  let base;
4123
4424
  let specifier = "";
4124
4425
  for (const [kind, value] of parts) {
4125
- if (kind === "base") {
4426
+ if (kind === "repair") {
4427
+ repairedAssets.add(assetName);
4428
+ } else if (kind === "base") {
4126
4429
  base = /** @type {string} */ (value);
4127
4430
  } else if (kind === "literal") {
4128
4431
  specifier += value;
@@ -4193,7 +4496,7 @@ class RuntimeTemplate {
4193
4496
  // the chunk loader does. A literal part may still carry a stand-in of its own,
4194
4497
  // so finish those here rather than scanning again.
4195
4498
  return fillFullHash(
4196
- /^(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(specifier)
4499
+ RESOLVABLE_SPECIFIER_REGEXP.test(specifier)
4197
4500
  ? specifier
4198
4501
  : `./${specifier}`
4199
4502
  );
@@ -4246,6 +4549,8 @@ class RuntimeTemplate {
4246
4549
 
4247
4550
  tasks.push({ name, source, replacements });
4248
4551
  }
4552
+ compilation.runtimeTemplate._analyzableRepairedAssets =
4553
+ repairedAssets;
4249
4554
  if (tasks.length === 0) return;
4250
4555
 
4251
4556
  await Promise.all(