@depup/webpack 5.110.3-depup.0 → 5.111.1-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +7 -8
  2. package/changes.json +7 -11
  3. package/lib/APIPlugin.js +26 -11
  4. package/lib/AutomaticPrefetchPlugin.js +1 -1
  5. package/lib/Cache.js +8 -3
  6. package/lib/CacheFacade.js +1 -1
  7. package/lib/CircularModulesPlugin.js +157 -55
  8. package/lib/CleanPlugin.js +2 -2
  9. package/lib/CompatibilityPlugin.js +3 -4
  10. package/lib/Compilation.js +336 -337
  11. package/lib/Compiler.js +213 -51
  12. package/lib/ConstPlugin.js +16 -132
  13. package/lib/CopyPlugin.js +1054 -0
  14. package/lib/DefinePlugin.js +24 -8
  15. package/lib/DependencyTemplate.js +2 -1
  16. package/lib/DotenvPlugin.js +24 -28
  17. package/lib/ErrorHelpers.js +113 -0
  18. package/lib/ExportsInfo.js +20 -16
  19. package/lib/ExternalModule.js +47 -22
  20. package/lib/FileSystemInfo.js +17 -14
  21. package/lib/FlagDependencyExportsPlugin.js +53 -34
  22. package/lib/FlagDependencyUsagePlugin.js +9 -13
  23. package/lib/Generator.js +24 -2
  24. package/lib/HotModuleReplacementPlugin.js +55 -7
  25. package/lib/IgnorePlugin.js +1 -1
  26. package/lib/JavascriptMetaInfoPlugin.js +5 -3
  27. package/lib/LoaderOptionsPlugin.js +1 -1
  28. package/lib/MainTemplate.js +5 -1
  29. package/lib/Module.js +19 -10
  30. package/lib/ModuleGraph.js +6 -9
  31. package/lib/MultiCompiler.js +7 -17
  32. package/lib/MultiWatching.js +1 -1
  33. package/lib/NormalModule.js +135 -50
  34. package/lib/NormalModuleFactory.js +1 -1
  35. package/lib/RuntimeGlobals.js +21 -7
  36. package/lib/RuntimeModule.js +28 -12
  37. package/lib/RuntimePlugin.js +30 -3
  38. package/lib/RuntimeTemplate.js +813 -518
  39. package/lib/SourceMapDevToolPlugin.js +54 -104
  40. package/lib/TemplatedPathPlugin.js +16 -59
  41. package/lib/Watching.js +9 -0
  42. package/lib/WebpackOptionsApply.js +84 -91
  43. package/lib/asset/AssetBytesGenerator.js +7 -1
  44. package/lib/asset/AssetGenerator.js +50 -24
  45. package/lib/asset/AssetModule.js +3 -0
  46. package/lib/asset/AssetSourceGenerator.js +7 -1
  47. package/lib/asset/WebManifestParser.js +7 -5
  48. package/lib/buildChunkGraph.js +11 -15
  49. package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
  50. package/lib/cache/IdleFileCachePlugin.js +2 -2
  51. package/lib/cache/MemoryCachePlugin.js +4 -4
  52. package/lib/cache/MemoryWithGcCachePlugin.js +7 -8
  53. package/lib/cache/PackFileCacheStrategy.js +17 -19
  54. package/lib/cache/getLazyHashedEtag.js +3 -5
  55. package/lib/config/browserslistTargetHandler.js +17 -4
  56. package/lib/config/defaults.js +138 -128
  57. package/lib/config/getClaimedAssetTypes.js +10 -11
  58. package/lib/config/normalization.js +82 -12
  59. package/lib/config/target.js +13 -4
  60. package/lib/container/ContainerReferencePlugin.js +6 -0
  61. package/lib/container/RemoteRuntimeModule.js +9 -0
  62. package/lib/container/declaredRemotes.js +39 -0
  63. package/lib/{ContextExclusionPlugin.js → context/ContextExclusionPlugin.js} +1 -1
  64. package/lib/{ContextModule.js → context/ContextModule.js} +54 -115
  65. package/lib/{ContextModuleFactory.js → context/ContextModuleFactory.js} +19 -21
  66. package/lib/{ContextReplacementPlugin.js → context/ContextReplacementPlugin.js} +4 -4
  67. package/lib/css/CssGenerator.js +27 -11
  68. package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
  69. package/lib/css/CssLoadingRuntimeModule.js +94 -36
  70. package/lib/css/CssModule.js +1 -1
  71. package/lib/css/CssModulesPlugin.js +7 -6
  72. package/lib/css/CssParser.js +162 -31
  73. package/lib/css/CssServerStylesRuntimeModule.js +9 -0
  74. package/lib/css/cssMinify.js +43 -32
  75. package/lib/css/data.js +3514 -869
  76. package/lib/css/syntax.js +6370 -1220
  77. package/lib/debug/ProfilingPlugin.js +7 -4
  78. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
  79. package/lib/dependencies/AMDRuntimeModules.js +18 -0
  80. package/lib/dependencies/CommonJsExportRequireDependency.js +13 -12
  81. package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
  82. package/lib/dependencies/CommonJsImportsParserPlugin.js +5 -5
  83. package/lib/dependencies/CommonJsPlugin.js +19 -3
  84. package/lib/dependencies/CommonJsRequireDependency.js +14 -5
  85. package/lib/dependencies/CommonJsSelfReferenceDependency.js +2 -4
  86. package/lib/dependencies/ContextDependency.js +1 -1
  87. package/lib/dependencies/ContextDependencyHelpers.js +3 -9
  88. package/lib/dependencies/ContextElementDependency.js +1 -1
  89. package/lib/dependencies/CssIcssExportDependency.js +13 -9
  90. package/lib/dependencies/CssIcssImportDependency.js +3 -6
  91. package/lib/dependencies/CssUrlDependency.js +3 -5
  92. package/lib/dependencies/HarmonyCompatibilityDependency.js +67 -22
  93. package/lib/dependencies/HarmonyDetectionParserPlugin.js +3 -4
  94. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +10 -7
  95. package/lib/dependencies/HarmonyExportExpressionDependency.js +47 -33
  96. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +74 -17
  97. package/lib/dependencies/HarmonyExportInitFragment.js +110 -23
  98. package/lib/dependencies/HarmonyExportSpecifierDependency.js +25 -58
  99. package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
  100. package/lib/dependencies/HarmonyImportDependency.js +6 -1
  101. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +111 -17
  102. package/lib/dependencies/HarmonyImportSideEffectDependency.js +3 -4
  103. package/lib/dependencies/HarmonyImportSpecifierDependency.js +40 -3
  104. package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
  105. package/lib/dependencies/HtmlEntryDependency.js +124 -102
  106. package/lib/dependencies/HtmlInlineScriptDependency.js +3 -4
  107. package/lib/dependencies/HtmlInlineStyleDependency.js +3 -4
  108. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  109. package/lib/dependencies/ImportMetaGlobHelpers.js +1 -1
  110. package/lib/dependencies/ImportMetaMainDependency.js +104 -0
  111. package/lib/dependencies/ImportMetaPlugin.js +67 -25
  112. package/lib/dependencies/ImportParserPlugin.js +1 -1
  113. package/lib/dependencies/LoaderPlugin.js +26 -1
  114. package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
  115. package/lib/dependencies/SystemRuntimeModule.js +9 -0
  116. package/lib/dependencies/URLContextDependency.js +1 -1
  117. package/lib/dependencies/URLDependency.js +6 -5
  118. package/lib/dependencies/WorkerAndWorkletPlugin.js +15 -21
  119. package/lib/dependencies/WorkerDependency.js +7 -7
  120. package/lib/dependencies/WorkletDependency.js +7 -11
  121. package/lib/dll/DelegatedModule.js +18 -1
  122. package/lib/dll/DllReferencePlugin.js +11 -8
  123. package/lib/dll/LibManifestPlugin.js +1 -1
  124. package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
  125. package/lib/errors/DuplicateModulesWarning.js +12 -7
  126. package/lib/errors/EmptyCopyPatternWarning.js +26 -0
  127. package/lib/errors/ExternalStarReexportError.js +44 -0
  128. package/lib/errors/HookWebpackError.js +3 -2
  129. package/lib/errors/MissingSourceMapsWarning.js +36 -0
  130. package/lib/errors/ModuleParseError.js +2 -1
  131. package/lib/errors/UnusedAssetsWarning.js +36 -0
  132. package/lib/errors/UnusedFederationWarning.js +35 -0
  133. package/lib/errors/UnusedModulesWarning.js +38 -0
  134. package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
  135. package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
  136. package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
  137. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
  138. package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
  139. package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
  140. package/lib/hmr/LazyCompilationPlugin.js +3 -5
  141. package/lib/html/HtmlGenerator.js +72 -87
  142. package/lib/html/HtmlModulesPlugin.js +418 -200
  143. package/lib/html/HtmlParser.js +110 -147
  144. package/lib/html/builtinEmbeddedRenderer.js +107 -0
  145. package/lib/html/data.js +142 -7
  146. package/lib/html/htmlMinify.js +92 -122
  147. package/lib/html/syntax.js +1618 -1391
  148. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  149. package/lib/index.js +49 -3
  150. package/lib/javascript/ChunkFormatHelpers.js +4 -3
  151. package/lib/javascript/JavascriptGenerator.js +8 -1
  152. package/lib/javascript/JavascriptModule.js +1 -0
  153. package/lib/javascript/JavascriptModulesPlugin.js +73 -72
  154. package/lib/javascript/JavascriptParser.js +1970 -900
  155. package/lib/javascript/StartupHelpers.js +27 -3
  156. package/lib/javascript/data.js +172 -0
  157. package/lib/javascript/grammar.js +5546 -0
  158. package/lib/javascript/parser.js +1500 -0
  159. package/lib/javascript/regexp.js +1762 -0
  160. package/lib/javascript/regexpData.js +51 -0
  161. package/lib/javascript/syntax.js +9061 -5262
  162. package/lib/json/JsonGenerator.js +7 -1
  163. package/lib/library/ModuleLibraryPlugin.js +171 -132
  164. package/lib/loaders/LoaderRunner.js +137 -9
  165. package/lib/node/NodeWatchFileSystem.js +3 -9
  166. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
  167. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
  168. package/lib/optimize/AggressiveMergingPlugin.js +3 -5
  169. package/lib/optimize/ConcatenatedModule.js +178 -120
  170. package/lib/optimize/ConstExportsPlugin.js +50 -39
  171. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -11
  172. package/lib/optimize/InlineExports.js +20 -123
  173. package/lib/optimize/InnerGraphPlugin.js +7 -13
  174. package/lib/optimize/LimitChunkCountPlugin.js +5 -8
  175. package/lib/optimize/MangleExportsPlugin.js +13 -4
  176. package/lib/optimize/ModuleConcatenationPlugin.js +27 -5
  177. package/lib/optimize/RealContentHashPlugin.js +68 -9
  178. package/lib/optimize/SideEffectsFlagPlugin.js +24 -28
  179. package/lib/optimize/SplitChunksPlugin.js +2 -4
  180. package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
  181. package/lib/performance/BroadContextsPlugin.js +1 -1
  182. package/lib/performance/CacheEffectivenessPlugin.js +7 -7
  183. package/lib/performance/DuplicateModulesPlugin.js +57 -13
  184. package/lib/performance/EvalUsagePlugin.js +5 -2
  185. package/lib/performance/MissingSourceMapsPlugin.js +115 -0
  186. package/lib/performance/PureAnnotationsPlugin.js +6 -3
  187. package/lib/performance/SizeLimitsPlugin.js +2 -4
  188. package/lib/performance/TopLevelThisPlugin.js +5 -4
  189. package/lib/performance/UnusedAssetsPlugin.js +109 -0
  190. package/lib/performance/UnusedFederationPlugin.js +147 -0
  191. package/lib/performance/UnusedModulesPlugin.js +141 -0
  192. package/lib/performance/UnusedReexportsPlugin.js +1 -55
  193. package/lib/performance/isOnlyReexported.js +65 -0
  194. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
  195. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +8 -8
  196. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
  197. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
  198. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
  199. package/lib/prefetch/ResourceHintPlugin.js +18 -23
  200. package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
  201. package/lib/prefetch/StartupAssetHintRuntimeModule.js +16 -10
  202. package/lib/rules/RuleSetCompiler.js +211 -4
  203. package/lib/runtime/AsyncModuleRuntimeModule.js +98 -66
  204. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
  205. package/lib/runtime/BaseUriRuntimeModule.js +9 -0
  206. package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
  207. package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
  208. package/lib/runtime/GetChunkFilenameRuntimeModule.js +12 -4
  209. package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
  210. package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
  211. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
  212. package/lib/runtime/GlobalRuntimeModule.js +11 -4
  213. package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
  214. package/lib/runtime/HelperRuntimeModule.js +10 -0
  215. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +305 -224
  216. package/lib/runtime/NonceRuntimeModule.js +9 -0
  217. package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
  218. package/lib/runtime/PublicPathRuntimeModule.js +9 -0
  219. package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
  220. package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
  221. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
  222. package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
  223. package/lib/runtime/SystemContextRuntimeModule.js +9 -0
  224. package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
  225. package/lib/schemes/DataUriPlugin.js +3 -6
  226. package/lib/schemes/VirtualUrlPlugin.js +1 -1
  227. package/lib/serialization/BinaryMiddleware.js +9 -9
  228. package/lib/serialization/FileMiddleware.js +16 -16
  229. package/lib/serialization/ObjectMiddleware.js +168 -139
  230. package/lib/sharing/ConsumeSharedPlugin.js +12 -0
  231. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
  232. package/lib/sharing/ShareRuntimeModule.js +9 -0
  233. package/lib/sharing/declaredShared.js +47 -0
  234. package/lib/stats/DefaultStatsFactoryPlugin.js +6 -5
  235. package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
  236. package/lib/typescript/TypeScriptPlugin.js +2 -3
  237. package/lib/url/URLParserPlugin.js +6 -8
  238. package/lib/util/LocConverter.js +4 -7
  239. package/lib/util/SourceProcessor.js +91 -91
  240. package/lib/util/async.js +292 -0
  241. package/lib/util/buildDiagnostics.js +69 -0
  242. package/lib/util/chainedImports.js +3 -4
  243. package/lib/util/concatenate.js +4 -4
  244. package/lib/util/createHooksRegistry.js +1 -2
  245. package/lib/util/dataURL.js +2 -3
  246. package/lib/util/deterministicGrouping.js +8 -13
  247. package/lib/util/findGraphRoots.js +6 -13
  248. package/lib/util/fs.js +27 -1
  249. package/lib/util/globUtils.js +1 -1
  250. package/lib/util/handlerKeys.js +40 -0
  251. package/lib/util/hash/wasm-hash.js +3 -4
  252. package/lib/util/identifier.js +20 -0
  253. package/lib/util/internalSerializables.js +5 -1
  254. package/lib/util/registerExternalSerializer.js +6 -45
  255. package/lib/util/semver.js +5 -3
  256. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
  257. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
  258. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -1
  259. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -1
  260. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +12 -4
  261. package/lib/wasm-sync/WebAssemblyGenerator.js +6 -1
  262. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -1
  263. package/lib/wasm-sync/WebAssemblyUtils.js +2 -4
  264. package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
  265. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
  266. package/package.json +55 -46
  267. package/schemas/WebpackOptions.check.js +1 -1
  268. package/schemas/WebpackOptions.json +379 -66
  269. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  270. package/schemas/plugins/ManifestPlugin.check.js +1 -1
  271. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  272. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  273. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  274. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  275. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  276. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  277. package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
  278. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
  279. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  280. package/types.d.ts +1723 -604
  281. package/lib/dependencies/ExportBindingInitFragment.js +0 -191
  282. package/lib/errors/EntrypointOverlapWarning.js +0 -45
  283. 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:
@@ -659,14 +745,14 @@ class RuntimeTemplate {
659
745
  : undefined;
660
746
  // A reassigned `__webpack_public_path__` cannot reach a baked literal, and `.p`
661
747
  // belongs to a runtime, so only the runtimes it reaches keep the runtime form.
662
- // `url-inline` is unaffected: that form falls back to `.p + <file>`, which reads
663
- // the reassigned value at the call site rather than through the wrapper.
748
+ // `url-inline` is unaffected: it reads the value at the call site.
664
749
  if (
665
750
  form !== "url-inline" &&
666
751
  APIPlugin.runtimeUsesPublicPathOverride(
667
752
  this.compilation,
668
753
  scoped ? chunkGraph : undefined,
669
- placedModule
754
+ placedModule,
755
+ runtime
670
756
  )
671
757
  ) {
672
758
  return this._analyzableBailout(
@@ -678,57 +764,31 @@ class RuntimeTemplate {
678
764
 
679
765
  if (form === "import") {
680
766
  // 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
- }
767
+ const outputReason = this._chunkImportOutputReason();
768
+ if (outputReason !== null) {
769
+ return this._analyzableBailout(module, outputReason, false);
710
770
  }
771
+ // A worker loading its own chunks some other way needs no answer here: it gets
772
+ // a chunk loader of its own, and only the ESM one asks this.
711
773
  return true;
712
774
  }
713
775
 
714
- // `url-inline` asks whether the file can be named at the call site at all, and
715
- // its `.p + <file>` fallback spells that without `import.meta` — so the gate
716
- // below does not rule it out, and the asset's javascript wrapper stays dropped.
776
+ // `url-inline` asks only whether the file can be named at the call site, and
777
+ // its `.p + <file>` fallback spells that without `import.meta`, so the gate
778
+ // below does not rule it out.
779
+
717
780
  // `environment.module` is deliberately not consulted: ESM output writes
718
- // `import.meta` regardless (the public path, the chunk loader), so the url forms
719
- // only match what the rest of the bundle already assumes the target reads.
781
+ // `import.meta` regardless, so the url forms match what the rest of the
782
+ // bundle already assumes the target reads.
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,17 +1122,15 @@ 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
- // A protocol-relative base names a host but no scheme, and the runtime reads it
1029
- // against the chunk's own url to get one — the very url this literal is
1030
- // resolved against — so it may stay protocol-relative instead of being settled
1031
- // here. Nothing walks back to the output root first: the base replaces it.
1127
+ // A protocol-relative base names a host but no scheme, and the runtime reads
1128
+ // it against the very url this literal resolves against, so it may stay that
1129
+ // way. Nothing walks back to the output root: the base replaces it.
1032
1130
  if (base.startsWith("//")) {
1033
1131
  return this._specifierOf(
1034
1132
  [["literal", base], ...rootedParts(parts), ["literal", filename]],
1035
- chunks,
1036
- module
1133
+ chunks
1037
1134
  );
1038
1135
  }
1039
1136
  if (!isAbsoluteBaseUri(base)) {
@@ -1065,13 +1162,14 @@ class RuntimeTemplate {
1065
1162
  );
1066
1163
  }
1067
1164
  if (text !== null) return toJsStringLiteral(resolved.href);
1068
- if (!this._canDeferOrBail(chunks, module)) return null;
1069
1165
  return toJsStringLiteral(
1070
- this._reserveAnalyzableSpecifier([
1071
- ["base", base],
1072
- ...parts,
1073
- ["literal", filename]
1074
- ])
1166
+ this._reserveAnalyzableSpecifier(
1167
+ this._markedForRepair(this._needsRepair(chunks), [
1168
+ ["base", base],
1169
+ ...parts,
1170
+ ["literal", filename]
1171
+ ])
1172
+ )
1075
1173
  );
1076
1174
  }
1077
1175
 
@@ -1093,10 +1191,9 @@ class RuntimeTemplate {
1093
1191
  let base;
1094
1192
  let found = false;
1095
1193
  for (const chunk of this.compilation.chunks) {
1096
- // What a literal has to agree with is the one value `BaseUriRuntimeModule`
1097
- // writes out, and it reads the entry options off the chunk it is emitted into
1098
- // — so only a chunk carrying a runtime has a say. Entries sharing one runtime
1099
- // chunk already share the base it sets, however their descriptors differ.
1194
+ // A literal must agree with the one value `BaseUriRuntimeModule` writes, and
1195
+ // that reads the entry options off the chunk it is emitted into, so only a
1196
+ // chunk carrying a runtime has a say.
1100
1197
  if (!chunk.hasRuntime()) continue;
1101
1198
  const entryOptions = chunk.getEntryOptions();
1102
1199
  // An entry this code cannot run under has no say in the base it resolves to.
@@ -1384,14 +1481,13 @@ class RuntimeTemplate {
1384
1481
  }
1385
1482
  if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
1386
1483
 
1387
- // cost comparison between template literal and concatenation:
1388
- // both need equal surroundings: `xxx` vs "xxx"
1389
- // template literal has constant cost of 3 chars for each expression
1390
- // es5 concatenation has cost of 3 + n chars for n expressions in row
1391
- // when a es5 concatenation ends with an expression it reduces cost by 3
1392
- // when a es5 concatenation starts with an single expression it reduces cost by 3
1393
- // e. g. `${a}${b}${c}` (3*3 = 9) is longer than ""+a+b+c ((3+3)-3 = 3)
1394
- // e. g. `x${a}x${b}x${c}x` (3*3 = 9) is shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12)
1484
+ // WHY: cost comparison between a template literal and a concatenation, both
1485
+ // needing equal surroundings (`xxx` against "xxx"). A template literal costs
1486
+ // a constant 3 chars per expression; an es5 concatenation costs 3 + n chars
1487
+ // for n expressions in a row, and reduces by 3 where it ends with an
1488
+ // expression or starts with a single one. So `${a}${b}${c}` (3*3 = 9) is
1489
+ // longer than ""+a+b+c ((3+3)-3 = 3), while `x${a}x${b}x${c}x` (3*3 = 9) is
1490
+ // shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12).
1395
1491
 
1396
1492
  let templateCost = 0;
1397
1493
  let concatenationCost = 0;
@@ -1868,14 +1964,21 @@ class RuntimeTemplate {
1868
1964
  });
1869
1965
  const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
1870
1966
  switch (exportsType) {
1871
- case "namespace":
1872
- return this.moduleRaw({
1967
+ case "namespace": {
1968
+ const raw = this.moduleRaw({
1873
1969
  module,
1874
1970
  chunkGraph,
1875
1971
  request,
1876
1972
  weak,
1877
1973
  runtimeRequirements
1878
1974
  });
1975
+
1976
+ if (!usesSpecNamespaceObject(module)) return raw;
1977
+
1978
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
1979
+
1980
+ return `${RuntimeGlobals.specNamespaceObject}(${raw})`;
1981
+ }
1879
1982
  case "default-with-named":
1880
1983
  runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
1881
1984
  return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`;
@@ -1984,6 +2087,21 @@ class RuntimeTemplate {
1984
2087
 
1985
2088
  let mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
1986
2089
  if (mode) mode = `${mode} | 16`;
2090
+ // The spec's namespace keys are the sorted exports, so hand them over
2091
+ // when they are fully known; otherwise the runtime stays permissive.
2092
+ const deferredExportNames = getKnownExportNames(
2093
+ chunkGraph.moduleGraph,
2094
+ module,
2095
+ exportsType
2096
+ );
2097
+ runtimeRequirements.add(
2098
+ deferredExportNames
2099
+ ? RuntimeGlobals.hasSealedDeferredNamespace
2100
+ : RuntimeGlobals.hasSynthesizedDeferredNamespace
2101
+ );
2102
+ mode += deferredExportNames
2103
+ ? `, ${JSON.stringify(deferredExportNames)}`
2104
+ : "";
1987
2105
 
1988
2106
  const asyncDeps = Array.from(
1989
2107
  getOutgoingAsyncModules(chunkGraph.moduleGraph, module),
@@ -2027,15 +2145,22 @@ class RuntimeTemplate {
2027
2145
  } else {
2028
2146
  let fakeType = 16;
2029
2147
  switch (exportsType) {
2030
- case "namespace":
2031
- if (header) {
2032
- const rawModule = this.moduleRaw({
2148
+ case "namespace": {
2149
+ const specNamespace = usesSpecNamespaceObject(module);
2150
+ const asyncModule = chunkGraph.moduleGraph.isAsync(module);
2151
+ if (header || (specNamespace && !asyncModule)) {
2152
+ let rawModule = this.moduleRaw({
2033
2153
  module,
2034
2154
  chunkGraph,
2035
2155
  request,
2036
2156
  weak,
2037
2157
  runtimeRequirements
2038
2158
  });
2159
+ if (specNamespace && !asyncModule) {
2160
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2161
+ // Wrap before promise resolution assimilates an exported `then`.
2162
+ rawModule = `${RuntimeGlobals.specNamespaceObject}(${rawModule})`;
2163
+ }
2039
2164
  appending = `.then(${this.basicFunction(
2040
2165
  "",
2041
2166
  `${header}return ${rawModule};`
@@ -2047,7 +2172,14 @@ class RuntimeTemplate {
2047
2172
  `${comment}${idExpr}`
2048
2173
  )})`;
2049
2174
  }
2175
+
2176
+ if (specNamespace && asyncModule) {
2177
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2178
+ appending += `.then(${RuntimeGlobals.specNamespaceObject})`;
2179
+ }
2180
+
2050
2181
  break;
2182
+ }
2051
2183
  case "dynamic":
2052
2184
  fakeType |= 4;
2053
2185
  /* fall through */
@@ -2101,6 +2233,15 @@ class RuntimeTemplate {
2101
2233
  )})`;
2102
2234
  }
2103
2235
  }
2236
+ if (synthesizesSpecNamespaceObject(originModule)) {
2237
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2238
+ runtimeRequirements.add(RuntimeGlobals.moduleCache);
2239
+ const owner = synthesizedNamespaceOwner(moduleId, fakeType);
2240
+ appending += `.then(${this.returningFunction(
2241
+ `${RuntimeGlobals.specNamespaceObject}(m${owner})`,
2242
+ "m"
2243
+ )})`;
2244
+ }
2104
2245
  break;
2105
2246
  }
2106
2247
  }
@@ -2209,10 +2350,9 @@ class RuntimeTemplate {
2209
2350
  request,
2210
2351
  weak
2211
2352
  });
2212
- // Harmony imports may be wrapped in runtime-condition `if` blocks
2213
- // but referenced outside those blocks (e.g. by harmony reexport),
2214
- // so they must remain function-scoped (`var`) rather than
2215
- // block-scoped (`let`/`const`).
2353
+ // A harmony import may sit inside a runtime-condition `if` block yet be
2354
+ // referenced outside it, so it stays function-scoped with `var` rather than
2355
+ // block-scoped.
2216
2356
  const optDeclaration = update ? "" : "var ";
2217
2357
 
2218
2358
  const exportsType = module.getExportsType(
@@ -2351,10 +2491,8 @@ class RuntimeTemplate {
2351
2491
  }
2352
2492
  // accessing the .default property is same thing as `require()` the module.
2353
2493
 
2354
- // For example:
2355
- // import mod from "cjs"; mod.default.x;
2356
- // is translated to
2357
- // var mod = require("cjs"); mod.x;
2494
+ // So `import mod from "cjs"; mod.default.x` translates to
2495
+ // `var mod = require("cjs"); mod.x`.
2358
2496
  switch (exportsType) {
2359
2497
  case "dynamic":
2360
2498
  if (isCall) {
@@ -2394,10 +2532,9 @@ class RuntimeTemplate {
2394
2532
  exportsType === "default-only" ||
2395
2533
  exportsType === "default-with-named"
2396
2534
  ) {
2397
- // now exportName.length is 0, which means the namespace object is used in an unknown way
2398
- // for example:
2399
- // import * as ns from "cjs"; console.log(ns);
2400
- // we will need to createFakeNamespaceObject that simulates ES Module namespace object
2535
+ // `exportName.length` is 0, so the namespace object is used in an unknown
2536
+ // way — `import * as ns from "cjs"; console.log(ns)` — and needs
2537
+ // `createFakeNamespaceObject` to simulate an ES module namespace.
2401
2538
  runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
2402
2539
  initFragments.push(
2403
2540
  new InitFragment(
@@ -2407,16 +2544,38 @@ class RuntimeTemplate {
2407
2544
  `${importVar}_namespace_cache`
2408
2545
  )
2409
2546
  );
2547
+ const fakeMode = exportsType === "default-only" ? 0 : 2;
2548
+ const fakeArguments = fakeMode === 0 ? "" : ", 2";
2549
+ let fakeNamespace = `${RuntimeGlobals.createFakeNamespaceObject}(${importVar}${fakeArguments})`;
2550
+ if (synthesizesSpecNamespaceObject(originModule)) {
2551
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2552
+ runtimeRequirements.add(RuntimeGlobals.moduleCache);
2553
+ const owner = synthesizedNamespaceOwner(
2554
+ chunkGraph.getModuleId(module),
2555
+ fakeMode
2556
+ );
2557
+ fakeNamespace = `${RuntimeGlobals.specNamespaceObject}(${fakeNamespace}${owner})`;
2558
+ }
2410
2559
  return `/*#__PURE__*/ ${
2411
2560
  asiSafe ? "" : asiSafe === false ? ";" : "Object"
2412
- }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${
2413
- RuntimeGlobals.createFakeNamespaceObject
2414
- }(${importVar}${exportsType === "default-only" ? "" : ", 2"})))`;
2561
+ }(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${fakeNamespace}))`;
2415
2562
  }
2416
2563
  }
2417
2564
 
2418
2565
  if (exportName.length > 0) {
2419
2566
  const exportsInfo = moduleGraph.getExportsInfo(module);
2567
+ // A name the module does not export is the namespace's to answer — reading
2568
+ // it is undefined and writing it fails — not the exports object's.
2569
+ if (
2570
+ !isModuleDeferred &&
2571
+ usesSpecNamespaceObject(module) &&
2572
+ exportsInfo.isExportProvided(exportName) === false
2573
+ ) {
2574
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2575
+ const ns = `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
2576
+
2577
+ return `${ns}${propertyAccess(exportName)}`;
2578
+ }
2420
2579
  // in some case the exported item is renamed (get this by getUsedName). for example,
2421
2580
  // x.default might be emitted as x.Z (default is renamed to Z)
2422
2581
  const used = exportsInfo.getUsedName(exportName, runtime);
@@ -2461,9 +2620,19 @@ class RuntimeTemplate {
2461
2620
  runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
2462
2621
  const id = chunkGraph.getModuleId(module);
2463
2622
  const type = getMakeDeferredNamespaceModeFromExportsType(exportsType);
2464
- const init = `${
2465
- RuntimeGlobals.makeDeferredNamespaceObject
2466
- }(${JSON.stringify(id)}, ${type})`;
2623
+ const names = getKnownExportNames(
2624
+ chunkGraph.moduleGraph,
2625
+ module,
2626
+ exportsType
2627
+ );
2628
+ runtimeRequirements.add(
2629
+ names
2630
+ ? RuntimeGlobals.hasSealedDeferredNamespace
2631
+ : RuntimeGlobals.hasSynthesizedDeferredNamespace
2632
+ );
2633
+ const init = `${RuntimeGlobals.makeDeferredNamespaceObject}(${JSON.stringify(
2634
+ id
2635
+ )}, ${type}${names ? `, ${JSON.stringify(names)}` : ""})`;
2467
2636
 
2468
2637
  return `/*#__PURE__*/ ${
2469
2638
  asiSafe ? "" : asiSafe === false ? ";" : "Object"
@@ -2490,6 +2659,16 @@ class RuntimeTemplate {
2490
2659
  // if we hit here, the importVar is either
2491
2660
  // - already a ES module namespace object
2492
2661
  // - or imported by a way that does not need interop.
2662
+ if (
2663
+ exportsType === "namespace" &&
2664
+ exportName.length === 0 &&
2665
+ usesSpecNamespaceObject(module)
2666
+ ) {
2667
+ runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
2668
+
2669
+ return `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
2670
+ }
2671
+
2493
2672
  return importVar;
2494
2673
  }
2495
2674
 
@@ -2570,7 +2749,7 @@ class RuntimeTemplate {
2570
2749
  * @param {string} options.message the message
2571
2750
  * @param {ChunkGraph} options.chunkGraph the chunk graph
2572
2751
  * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
2573
- * @param {Module=} options.originModule the module the `import()` is emitted into
2752
+ * @param {Module=} options.originModule the module the `import()` is emitted into, to report against
2574
2753
  * @returns {string} expression
2575
2754
  */
2576
2755
  blockPromise({
@@ -2600,156 +2779,32 @@ class RuntimeTemplate {
2600
2779
  message,
2601
2780
  chunkName: block.chunkName
2602
2781
  });
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;
2782
+ // An output that cannot use a native `import()` gets no ESM chunk loader to ask,
2783
+ // so the reason is recorded here, where any build generates its imports.
2784
+ if (this.outputOptions.module && originModule !== undefined) {
2785
+ const outputReason = this._chunkImportOutputReason();
2786
+ if (outputReason !== null) {
2787
+ this._analyzableBailout(originModule, outputReason, false);
2675
2788
  }
2676
2789
  }
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;
2790
+ const fetchPriority = chunkGroup.options.fetchPriority;
2791
+ const priorityArg = fetchPriority
2792
+ ? `, ${JSON.stringify(fetchPriority)}`
2793
+ : "";
2794
+ if (chunks.length === 0) return `Promise.resolve(${comment.trim()})`;
2795
+ runtimeRequirements.add(RuntimeGlobals.ensureChunk);
2796
+ if (fetchPriority) {
2797
+ runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
2706
2798
  }
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
- );
2799
+ if (chunks.length === 1) {
2800
+ const chunkId = JSON.stringify(chunks[0].id);
2801
+ return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${priorityArg})`;
2716
2802
  }
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
2803
+ const items = chunks.map(
2804
+ (chunk) =>
2805
+ `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${priorityArg})`
2724
2806
  );
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})`)})`;
2807
+ return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
2753
2808
  }
2754
2809
 
2755
2810
  /**
@@ -2785,6 +2840,17 @@ class RuntimeTemplate {
2785
2840
  const late = this._settlesLate(chunk);
2786
2841
  if (late !== this._settlesLate(target)) return !late;
2787
2842
  }
2843
+ return this._hashRoundBefore(chunk, target);
2844
+ }
2845
+
2846
+ /**
2847
+ * Whether the four rounds alone settle `chunk` before `target`, leaving out what the
2848
+ * full-hash marks move: the order a runtime module generated in its chunk's round sees.
2849
+ * @param {Chunk} chunk the chunk whose hash would be read
2850
+ * @param {Chunk} target the chunk reading it
2851
+ * @returns {boolean} true when the hash exists by the time the target is hashed
2852
+ */
2853
+ _hashRoundBefore(chunk, target) {
2788
2854
  const chunkGraph = /** @type {ChunkGraph} */ (this.compilation.chunkGraph);
2789
2855
  const round = hashRound(chunk, chunkGraph);
2790
2856
  const targetRound = hashRound(target, chunkGraph);
@@ -2807,6 +2873,42 @@ class RuntimeTemplate {
2807
2873
  );
2808
2874
  }
2809
2875
 
2876
+ /**
2877
+ * Whether a `[chunkhash]`/`[contenthash]` name is settled before every chunk it is
2878
+ * written into, so a runtime module generated in its chunk's round can spell it.
2879
+ * @param {Chunk} chunk the chunk named
2880
+ * @param {string} template what names it
2881
+ * @param {Iterable<Chunk>} targets the chunks the name is written into
2882
+ * @returns {boolean} true when the hashes it reads exist by then
2883
+ */
2884
+ _hashedNameSettledBefore(chunk, template, targets) {
2885
+ const kinds = getTemplatedPathPlugin().getPresentKinds(template);
2886
+ // The compilation hash exists in no round a chunk is hashed in.
2887
+ if (kinds.has("fullhash") || kinds.has("hash")) return false;
2888
+ for (const target of targets) {
2889
+ if (!this._hashRoundBefore(chunk, target)) return false;
2890
+ }
2891
+ return true;
2892
+ }
2893
+
2894
+ /**
2895
+ * Whether the hashes a name reads are on the chunk now, which they are only once its
2896
+ * round of `createHash` has run — never while modules are being generated.
2897
+ * @param {Chunk} chunk the chunk named
2898
+ * @param {string} template what names it
2899
+ * @param {string} sourceType which asset of the chunk it names
2900
+ * @returns {boolean} true when the name can be resolved here
2901
+ */
2902
+ _hashedNamePresent(chunk, template, sourceType) {
2903
+ const kinds = getTemplatedPathPlugin().getPresentKinds(template);
2904
+ return (
2905
+ !kinds.has("fullhash") &&
2906
+ !kinds.has("hash") &&
2907
+ (!kinds.has("chunkhash") || chunk.hash !== undefined) &&
2908
+ (!kinds.has("contenthash") || chunk.contentHash[sourceType] !== undefined)
2909
+ );
2910
+ }
2911
+
2810
2912
  /**
2811
2913
  * Whether `createHash` settles this chunk's hash in the round that runs after the
2812
2914
  * compilation hash rather than in one of the four before it. Asked of the chunk
@@ -3068,35 +3170,6 @@ class RuntimeTemplate {
3068
3170
  this._chunksByIdForFold = undefined;
3069
3171
  }
3070
3172
 
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
3173
  /**
3101
3174
  * The chunks a reference emitted into `module` is written into — the assets a
3102
3175
  * stand-in of ours would land in, and so the only ones a deferred fill could go
@@ -3212,7 +3285,7 @@ class RuntimeTemplate {
3212
3285
  * The `../` path from a chunk's own asset back to the output root. Hashes are
3213
3286
  * neutralized first: a runtime module is generated once to be hashed, before any
3214
3287
  * hash exists, so resolving one there throws — and `RuntimeModule.updateHash`
3215
- * swallows that, pinning the module's hash to the message.
3288
+ * lets that throw fail the build rather than hashing it.
3216
3289
  * @param {Chunk} chunk the chunk whose asset holds the reference
3217
3290
  * @param {boolean} enforceRelative whether the answer keeps a leading `./`
3218
3291
  * @returns {string} the path back to the output root
@@ -3243,7 +3316,10 @@ class RuntimeTemplate {
3243
3316
  * @returns {Placement} where a literal in it is read from
3244
3317
  */
3245
3318
  _modulePlacement(module, chunkGraph) {
3246
- return this._placementOf(this._moduleChunks(module, chunkGraph));
3319
+ return this._placementOf(
3320
+ this._moduleChunks(module, chunkGraph),
3321
+ isHotModule(module)
3322
+ );
3247
3323
  }
3248
3324
 
3249
3325
  /**
@@ -3262,11 +3338,12 @@ class RuntimeTemplate {
3262
3338
 
3263
3339
  /**
3264
3340
  * The one answer every chunk in `chunks` agrees on, with either half `null` where
3265
- * they do not.
3341
+ * they do not — under HMR the update chunk, which re-runs the module, has a say too.
3266
3342
  * @param {Iterable<Chunk>} chunks the chunks a literal is written into
3343
+ * @param {boolean=} hot whether a hot update can re-run what is written
3267
3344
  * @returns {Placement} where a literal in them is read from
3268
3345
  */
3269
- _placementOf(chunks) {
3346
+ _placementOf(chunks, hot = false) {
3270
3347
  /** @type {Placement | undefined} */
3271
3348
  let first;
3272
3349
  /** @type {string | null} */
@@ -3275,13 +3352,17 @@ class RuntimeTemplate {
3275
3352
  let loaded = null;
3276
3353
  for (const chunk of chunks) {
3277
3354
  const own = this._chunkPlacement(chunk);
3355
+ const ownUndo =
3356
+ hot && own.undo !== null && own.undo !== this._hotUpdateUndo(chunk)
3357
+ ? null
3358
+ : own.undo;
3278
3359
  if (first === undefined) {
3279
3360
  first = own;
3280
- undo = own.undo;
3361
+ undo = ownUndo;
3281
3362
  loaded = own.loaded;
3282
3363
  continue;
3283
3364
  }
3284
- if (undo !== own.undo) undo = null;
3365
+ if (undo !== ownUndo) undo = null;
3285
3366
  if (loaded !== own.loaded) loaded = null;
3286
3367
  }
3287
3368
  if (first === undefined) return NO_PLACEMENT;
@@ -3301,16 +3382,9 @@ class RuntimeTemplate {
3301
3382
  * @param {Chunk} chunk the worker's entry chunk
3302
3383
  * @param {Module} module the module the reference is emitted into
3303
3384
  * @param {ChunkGraph} chunkGraph the chunk graph
3304
- * @param {RuntimeRequirements} runtimeRequirements what the consuming chunk needs
3305
3385
  * @returns {string | null} a quoted literal, or `null` to fall back
3306
3386
  */
3307
- getAnalyzableWorkerUrl(
3308
- overridePublicPath,
3309
- chunk,
3310
- module,
3311
- chunkGraph,
3312
- runtimeRequirements
3313
- ) {
3387
+ getAnalyzableWorkerUrl(overridePublicPath, chunk, module, chunkGraph) {
3314
3388
  // Without an id nothing can name the chunk in a stand-in.
3315
3389
  if (
3316
3390
  chunk.id === null ||
@@ -3322,8 +3396,7 @@ class RuntimeTemplate {
3322
3396
  overridePublicPath,
3323
3397
  chunk,
3324
3398
  module,
3325
- chunkGraph,
3326
- runtimeRequirements
3399
+ chunkGraph
3327
3400
  );
3328
3401
  }
3329
3402
 
@@ -3336,12 +3409,11 @@ class RuntimeTemplate {
3336
3409
  * @param {Module | undefined} consumingModule the module the reference is emitted
3337
3410
  * into, or `undefined` when `consumingChunks` names where it goes instead
3338
3411
  * @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
3412
  * @param {Chunk[]=} consumingChunks the chunks the reference is written into, where
3342
3413
  * they are known without a module to read them from
3343
3414
  * @param {string=} sourceType which half of the chunk is named — its javascript by
3344
3415
  * default, or its stylesheet
3416
+ * @param {boolean=} hot whether a hot update can re-run what is written
3345
3417
  * @returns {string | null} a JS string literal or expression, or `null` to fall back to the runtime form
3346
3418
  */
3347
3419
  _getAnalyzableChunkSpecifier(
@@ -3349,117 +3421,113 @@ class RuntimeTemplate {
3349
3421
  chunk,
3350
3422
  consumingModule,
3351
3423
  chunkGraph,
3352
- runtimeRequirements,
3353
3424
  consumingChunks,
3354
- sourceType = JAVASCRIPT_TYPE
3425
+ sourceType = JAVASCRIPT_TYPE,
3426
+ hot = isHotModule(consumingModule)
3355
3427
  ) {
3356
3428
  const { compilation } = this;
3357
3429
  const { outputOptions } = compilation;
3358
3430
  const naming = CHUNK_ASSET_NAMING.get(sourceType);
3359
3431
  // Nothing here names this type's asset, so nothing can spell where it will be.
3360
3432
  if (naming === undefined) return null;
3361
- const template = this._resolveChunkFilenameTemplate(
3362
- naming.template(chunk, outputOptions),
3363
- chunk,
3364
- sourceType
3365
- );
3433
+ const template = this._chunkAssetTemplate(chunk, sourceType);
3366
3434
  if (template === null) return null;
3367
3435
  // A hashed name is settled long after this code is generated, so a stand-in is
3368
3436
  // emitted and filled in once the hash exists.
3369
3437
  const deferred = template === undefined || HASH_IN_FILENAME.test(template);
3370
3438
  // An id names the chunk in the stand-in, and one nothing could resolve would
3371
- // reach the bundle verbatim. The whole name is re-resolved later rather than
3372
- // carrying a stand-in of its own, so any hash spelling is fine here.
3373
- // One of the two always names where the reference goes.
3439
+ // reach the bundle verbatim. The whole name is re-resolved later, so any hash
3440
+ // spelling is fine here; one of the two always names the destination.
3374
3441
  const chunks =
3375
3442
  consumingChunks ||
3376
3443
  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
- });
3444
+ // An id names the chunk in the stand-in; `blockPromise` drops an id-less chunk
3445
+ // before asking, so the guard only keeps `null` out of a name.
3446
+ if (chunk.id === null) return null;
3447
+ // A runtime module is generated in its chunk's round of `createHash`, where a
3448
+ // hashed name settled earlier exists: spelled, so a hot update carries the new one.
3449
+ const settled =
3450
+ deferred &&
3451
+ template !== undefined &&
3452
+ this._hashedNamePresent(chunk, template, sourceType) &&
3453
+ this._namesBeforeAll(chunk, chunks);
3454
+ const canReserve = this._canDeferAnalyzableName(chunks);
3455
+ // A content-named consumer folds this name into its hash when it settles first;
3456
+ // what the fold cannot cover is repaired instead.
3457
+ const canFold = !canReserve && this._namesBeforeAll(chunk, chunks);
3458
+ const filename =
3459
+ deferred && !settled
3460
+ ? ""
3461
+ : compilation.getPath(/** @type {string} */ (template), {
3462
+ chunk,
3463
+ // Matches what names the asset, or a placeholder resolved here would
3464
+ // not be the one on disk.
3465
+ runtime: chunk.runtime,
3466
+ contentHashType: sourceType
3467
+ });
3411
3468
  /**
3412
3469
  * @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
3470
+ * @returns {string} the specifier already quoted
3415
3471
  */
3416
3472
  const specifier = (prefix) => {
3417
- if (!deferred) {
3473
+ if (!deferred || settled) {
3418
3474
  const text = literalText(prefix);
3419
3475
  if (text !== null) return toJsStringLiteral(text + filename);
3420
3476
  }
3421
- if (!canReserve && !(canFold && this._foldsWholeName(prefix, chunks))) {
3422
- return cannotReserve();
3423
- }
3477
+ const repair =
3478
+ !canReserve && !(canFold && this._foldsWholeName(prefix, chunks));
3424
3479
  return toJsStringLiteral(
3425
- this._reserveAnalyzableSpecifier([
3426
- ...prefix,
3427
- [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
3428
- ])
3480
+ this._reserveAnalyzableSpecifier(
3481
+ this._markedForRepair(repair, [
3482
+ ...prefix,
3483
+ // A settled name is carried as text: the fill would spell the same,
3484
+ // but only text of its own moves the runtime module's hash.
3485
+ settled
3486
+ ? ["literal", filename]
3487
+ : [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
3488
+ ])
3489
+ )
3429
3490
  );
3430
3491
  };
3431
3492
  if (overridePublicPath) {
3432
- const resolved = this._resolvePublicPathPrefix(
3433
- overridePublicPath,
3434
- consumingModule,
3435
- chunks
3436
- );
3493
+ const resolved = this._resolvePublicPathPrefix(overridePublicPath);
3437
3494
  return resolved === null ? null : specifier(resolved);
3438
3495
  }
3439
3496
  const { publicPath } = outputOptions;
3440
3497
  if (publicPath === "auto") {
3441
- const { undo } = this._placementOf(chunks);
3498
+ const { undo } = this._placementOf(chunks, hot);
3442
3499
  if (undo !== null) return specifier([["literal", undo]]);
3443
3500
  // Different depths — no one `../` path is right for every asset the reference
3444
3501
  // 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)}`;
3502
+ return specifier([["undo", ""]]);
3454
3503
  }
3455
3504
  const prefix = this._analyzablePathPrefix(
3456
3505
  consumingModule,
3457
3506
  chunkGraph,
3458
- chunks
3507
+ chunks,
3508
+ undefined,
3509
+ hot
3459
3510
  );
3460
3511
  return prefix === null ? null : specifier(prefix);
3461
3512
  }
3462
3513
 
3514
+ /**
3515
+ * The template this chunk's asset of `sourceType` is named by: `undefined` where a
3516
+ * function reads a hash, `null` where nothing here names that type or it answers nothing.
3517
+ * @param {Chunk} chunk the chunk
3518
+ * @param {string} sourceType which asset of the chunk
3519
+ * @returns {string | undefined | null} the template
3520
+ */
3521
+ _chunkAssetTemplate(chunk, sourceType) {
3522
+ const naming = CHUNK_ASSET_NAMING.get(sourceType);
3523
+ if (naming === undefined) return null;
3524
+ return this._resolveChunkFilenameTemplate(
3525
+ naming.template(chunk, this.outputOptions),
3526
+ chunk,
3527
+ sourceType
3528
+ );
3529
+ }
3530
+
3463
3531
  /**
3464
3532
  * The parts that go in front of a name so a literal read from the chunk holding it
3465
3533
  * reaches what the runtime would. A public path needing no base is the whole answer.
@@ -3473,18 +3541,24 @@ class RuntimeTemplate {
3473
3541
  * @param {ChunkGraph} chunkGraph the chunk graph
3474
3542
  * @param {Iterable<Chunk>} chunks the chunks a stand-in would be written into
3475
3543
  * @param {string=} relativeBase an entry `baseUri` read against the output root
3544
+ * @param {boolean=} hot whether a hot update can re-run what is written
3476
3545
  * @returns {SpecifierPart[] | null} the parts, or `null` having recorded why not
3477
3546
  */
3478
- _analyzablePathPrefix(module, chunkGraph, chunks, relativeBase) {
3547
+ _analyzablePathPrefix(
3548
+ module,
3549
+ chunkGraph,
3550
+ chunks,
3551
+ relativeBase,
3552
+ hot = isHotModule(module)
3553
+ ) {
3479
3554
  const publicPath = /** @type {PublicPath} */ (
3480
3555
  this.outputOptions.publicPath
3481
3556
  );
3482
3557
  const shape = this._publicPathShape();
3483
3558
  if (shape === undefined) return null;
3484
- const resolve = () =>
3485
- this._resolvePublicPathPrefix(publicPath, module, chunks);
3559
+ const resolve = () => this._resolvePublicPathPrefix(publicPath);
3486
3560
  if (isBaseIndependent(shape)) return resolve();
3487
- const { undo, loaded } = this._placementOf(chunks);
3561
+ const { undo, loaded } = this._placementOf(chunks, hot);
3488
3562
  // What a chunk the loader fetched climbs back out of. One of no depth leaves
3489
3563
  // nothing to climb, and then both answers put the same text in front.
3490
3564
  const served = this._publicPathClimb();
@@ -3518,12 +3592,9 @@ class RuntimeTemplate {
3518
3592
  * the deferred pass whole instead. A function is called for its value rather than
3519
3593
  * read as a template, so one whose answer moves with the hash is called again there.
3520
3594
  * @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
3595
  * @returns {SpecifierPart[] | null} the parts, or `null` when it cannot be known
3525
3596
  */
3526
- _resolvePublicPathPrefix(publicPath, module, chunks) {
3597
+ _resolvePublicPathPrefix(publicPath) {
3527
3598
  if (typeof publicPath === "function") {
3528
3599
  // One that answers nothing to a probe cannot be placed, absolute or not.
3529
3600
  if (this._publicPathShape() === undefined) return null;
@@ -3534,28 +3605,18 @@ class RuntimeTemplate {
3534
3605
  if (resolved !== null) return [["literal", resolved]];
3535
3606
  // Called again by the fill against the compilation hash, so what it answers
3536
3607
  // there is that hash by another name.
3537
- return this._canDeferOrBakeFullHash(true, chunks, module)
3538
- ? [["publicPath", ""]]
3539
- : null;
3608
+ return [["publicPath", ""]];
3540
3609
  }
3541
3610
  if (!publicPath.includes("[")) return [["literal", publicPath]];
3542
3611
  // A re-encoded digest cannot be spelled by a stand-in, so it stays a template.
3543
3612
  if (getTemplatedPathPlugin().usesFullHashDigest(publicPath)) {
3544
- return this._canDeferOrBakeFullHash(true, chunks, module)
3545
- ? [["template", publicPath]]
3546
- : null;
3613
+ return [["template", publicPath]];
3547
3614
  }
3548
3615
  const literal = this.compilation.getPath(
3549
3616
  publicPath,
3550
3617
  this._deferredFullHashPathData()
3551
3618
  );
3552
- return this._canDeferOrBakeFullHash(
3553
- this._hasReservedFullHash(literal),
3554
- chunks,
3555
- module
3556
- )
3557
- ? [["literal", literal]]
3558
- : null;
3619
+ return [["literal", literal]];
3559
3620
  }
3560
3621
 
3561
3622
  /**
@@ -3640,7 +3701,7 @@ class RuntimeTemplate {
3640
3701
  relativeBase
3641
3702
  );
3642
3703
  if (prefix === null) return null;
3643
- return this._specifierOf([...prefix, ...file], chunks, module);
3704
+ return this._specifierOf([...prefix, ...file], chunks);
3644
3705
  }
3645
3706
  // No public path to place it against, so the `../` path back to the output root
3646
3707
  // is the whole prefix. Different depths — no one is right for every asset the
@@ -3650,23 +3711,22 @@ class RuntimeTemplate {
3650
3711
  const parts = [undo === null ? ["undo", ""] : ["literal", undo]];
3651
3712
  if (relativeBase !== undefined) parts.push(["literal", relativeBase]);
3652
3713
  parts.push(...file);
3653
- return this._specifierOf(parts, chunks, module);
3714
+ return this._specifierOf(parts, chunks);
3654
3715
  }
3655
3716
 
3656
3717
  /**
3657
3718
  * 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
3719
+ * keyed by chunk id, or `null` when they have to keep the runtime
3720
+ * `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
3660
3721
  * and the plugin declaring what it needs ask this, so the two always agree. The
3661
3722
  * runtime hands an absolute url string to `link.href`, and so does this — the browser
3662
3723
  * 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.
3724
+ * the loader reads the url as text either way.
3665
3725
  * @param {Chunk} runtimeChunk the chunk holding the stylesheet loader
3666
3726
  * @param {ChunkGraph} chunkGraph the chunk graph
3667
3727
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3668
3728
  * @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
3729
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3670
3730
  */
3671
3731
  analyzableCssChunkUrls(
3672
3732
  runtimeChunk,
@@ -3698,14 +3758,14 @@ class RuntimeTemplate {
3698
3758
  /**
3699
3759
  * Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
3700
3760
  * 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
3761
+ * id, or `null` when they have to keep the runtime
3762
+ * `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
3703
3763
  * them and the plugin declaring what it needs ask this, so the two always agree.
3704
3764
  * @param {Chunk} runtimeChunk the chunk holding the hint handlers
3705
3765
  * @param {ChunkGraph} chunkGraph the chunk graph
3706
3766
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3707
3767
  * @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
3768
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3709
3769
  */
3710
3770
  analyzableChunkScriptUrls(
3711
3771
  runtimeChunk,
@@ -3742,17 +3802,156 @@ class RuntimeTemplate {
3742
3802
  );
3743
3803
  }
3744
3804
 
3805
+ /**
3806
+ * Why no chunk import of this build can be a native `import()`, read from the
3807
+ * output configuration alone, or `null` when nothing in it rules one out.
3808
+ * @returns {string | null} the reason
3809
+ */
3810
+ _chunkImportOutputReason() {
3811
+ const { chunkFormat, importFunctionName } = this.outputOptions;
3812
+ if (chunkFormat !== "module") {
3813
+ return `output.chunkFormat is ${JSON.stringify(chunkFormat)}, so chunks are not read through a native import()`;
3814
+ }
3815
+ if (importFunctionName !== "import") {
3816
+ return `output.importFunctionName is ${JSON.stringify(importFunctionName)}, so the call site is not a native import()`;
3817
+ }
3818
+ return null;
3819
+ }
3820
+
3821
+ /**
3822
+ * Records that this runtime reads its chunks some way other than a native
3823
+ * `import()`, so no literal can name what it loads. Recorded on the entries that
3824
+ * chose it, which is where the setting behind it lives.
3825
+ * @param {Chunk} chunk the runtime chunk
3826
+ * @param {ChunkGraph} chunkGraph the chunk graph
3827
+ * @returns {void}
3828
+ */
3829
+ reportChunkImportBailout(chunk, chunkGraph) {
3830
+ if (!this.outputOptions.module) return;
3831
+ const entryOptions = chunk.getEntryOptions();
3832
+ const chunkLoading =
3833
+ entryOptions && entryOptions.chunkLoading !== undefined
3834
+ ? entryOptions.chunkLoading
3835
+ : this.outputOptions.chunkLoading;
3836
+ if (chunkLoading === "import") return;
3837
+ const subject = entryOptions && entryOptions.worker ? "worker" : "runtime";
3838
+ const reason = `this ${subject} loads its chunks with ${JSON.stringify(chunkLoading)}, not "import"`;
3839
+ for (const module of chunkGraph.getChunkEntryModulesIterable(chunk)) {
3840
+ this._analyzableBailout(module, reason, false);
3841
+ }
3842
+ }
3843
+
3844
+ /**
3845
+ * The chunks this loader can be handed an id for: the ones held by a group outside
3846
+ * the initial wave, which is what an `import()` or a context map turns into an id.
3847
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3848
+ * @returns {Set<Chunk>} the chunks reachable from here through a non-initial group
3849
+ */
3850
+ _loadableChunks(runtimeChunk) {
3851
+ const queue = new Set(runtimeChunk.groupsIterable);
3852
+ /** @type {Set<Chunk>} */
3853
+ const chunks = new Set();
3854
+ for (const group of queue) {
3855
+ if (!group.isInitial()) {
3856
+ for (const chunk of group.chunks) chunks.add(chunk);
3857
+ }
3858
+ for (const child of group.childrenIterable) queue.add(child);
3859
+ }
3860
+ return chunks;
3861
+ }
3862
+
3863
+ /**
3864
+ * Whether the loader still needs to build a url from a chunk id, which is the case
3865
+ * for a chunk it can be asked for that `analyzableChunkImports` leaves unnamed: one
3866
+ * carrying a runtime of its own, or one a second entrypoint has at startup.
3867
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3868
+ * @param {ChunkGraph} chunkGraph the chunk graph
3869
+ * @returns {boolean} true when an id the map does not hold can reach the loader
3870
+ */
3871
+ chunkImportsNeedRuntimeUrl(runtimeChunk, chunkGraph) {
3872
+ const installed = new Set(runtimeChunk.getAllInitialChunks());
3873
+ for (const chunk of this._loadableChunks(runtimeChunk)) {
3874
+ if (chunk === runtimeChunk) continue;
3875
+ if (!chunk.hasRuntime() && !installed.has(chunk)) continue;
3876
+ if (JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) return true;
3877
+ }
3878
+ return false;
3879
+ }
3880
+
3881
+ /**
3882
+ * A literal `import()` specifier for every javascript chunk a runtime loads on
3883
+ * demand, keyed by chunk id, or `null` when one of them cannot be named here. The
3884
+ * map is written into the runtime chunk rather than at each import site, so a
3885
+ * hashed chunk name reaches no module that imports it.
3886
+ * @param {Chunk} runtimeChunk the chunk holding the chunk loader
3887
+ * @param {ChunkGraph} chunkGraph the chunk graph
3888
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3889
+ * @param {Module=} consumingModule the runtime module, where one exists to report against
3890
+ * @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
3891
+ */
3892
+ analyzableChunkImports(
3893
+ runtimeChunk,
3894
+ chunkGraph,
3895
+ runtimeRequirements,
3896
+ consumingModule
3897
+ ) {
3898
+ // The runtime names the scope `__webpack_public_path__` belongs to, so the
3899
+ // answer holds whether or not a runtime module is there to ask about.
3900
+ if (
3901
+ !this.supportsAnalyzable(
3902
+ "import",
3903
+ chunkGraph,
3904
+ consumingModule,
3905
+ runtimeChunk.runtime
3906
+ )
3907
+ ) {
3908
+ return null;
3909
+ }
3910
+ // An initial chunk and one carrying a runtime are both reached by a static
3911
+ // import, so naming either here would only make two hashes chase each other.
3912
+ const installed = new Set(runtimeChunk.getAllInitialChunks());
3913
+ /** @type {Chunk[]} */
3914
+ const chunks = [];
3915
+ for (const chunk of runtimeChunk.getAllReferencedChunks()) {
3916
+ if (
3917
+ chunk === runtimeChunk ||
3918
+ chunk.hasRuntime() ||
3919
+ installed.has(chunk) ||
3920
+ !JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)
3921
+ ) {
3922
+ continue;
3923
+ }
3924
+ chunks.push(chunk);
3925
+ }
3926
+ const specifiers = this._analyzableChunkSpecifiers(
3927
+ chunks,
3928
+ chunkGraph,
3929
+ consumingModule,
3930
+ [runtimeChunk],
3931
+ JAVASCRIPT_TYPE,
3932
+ runtimeRequirements
3933
+ );
3934
+ if (specifiers === null) return null;
3935
+ for (const [id, specifier] of specifiers) {
3936
+ // A bare specifier is a package name, so spell it relative the way the
3937
+ // runtime form's `.p + <file>` would have resolved it.
3938
+ if (!RESOLVABLE_SPECIFIER_REGEXP.test(specifier.slice(1))) {
3939
+ specifiers.set(id, `"./${specifier.slice(1)}`);
3940
+ }
3941
+ }
3942
+ return specifiers;
3943
+ }
3944
+
3745
3945
  /**
3746
3946
  * 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.
3947
+ * chunk id, or `null` as soon as one of them cannot be named here.
3749
3948
  * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
3750
3949
  * @param {ChunkGraph} chunkGraph the chunk graph
3751
3950
  * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
3752
3951
  * @param {Chunk[]} consumingChunks the chunks the urls are written into
3753
3952
  * @param {string} sourceType which asset of each chunk to name
3754
3953
  * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
3755
- * @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
3954
+ * @returns {Map<ChunkId, string> | null} the urls, or `null` to keep the runtime form
3756
3955
  */
3757
3956
  _analyzableChunkUrls(
3758
3957
  chunks,
@@ -3762,17 +3961,51 @@ class RuntimeTemplate {
3762
3961
  sourceType,
3763
3962
  runtimeRequirements
3764
3963
  ) {
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
- ) {
3964
+ if (!this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)) {
3771
3965
  return null;
3772
3966
  }
3967
+ const urls = this._analyzableChunkSpecifiers(
3968
+ chunks,
3969
+ chunkGraph,
3970
+ consumingModule,
3971
+ consumingChunks,
3972
+ sourceType,
3973
+ runtimeRequirements
3974
+ );
3975
+ if (urls === null) return null;
3976
+ for (const [id, specifier] of urls) {
3977
+ urls.set(id, `${this.importMetaUrl(specifier)}.href`);
3978
+ }
3979
+ return urls;
3980
+ }
3981
+
3982
+ /**
3983
+ * The quoted specifier naming one asset of each of `chunks`, keyed by chunk id, or
3984
+ * `null` as soon as one of them cannot be named here. What the name is read against
3985
+ * is the caller's: a url resolves it, an `import()` hands it to the loader.
3986
+ * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
3987
+ * @param {ChunkGraph} chunkGraph the chunk graph
3988
+ * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
3989
+ * @param {Chunk[]} consumingChunks the chunks the specifiers are written into
3990
+ * @param {string} sourceType which asset of each chunk to name
3991
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
3992
+ * @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
3993
+ */
3994
+ _analyzableChunkSpecifiers(
3995
+ chunks,
3996
+ chunkGraph,
3997
+ consumingModule,
3998
+ consumingChunks,
3999
+ sourceType,
4000
+ runtimeRequirements
4001
+ ) {
4002
+ // A hot update re-ships the runtime module only when its own code changes, so
4003
+ // each name has to be text nothing but an id joining or leaving the map can move.
4004
+ const hot = runtimeRequirements.has(
4005
+ RuntimeGlobals.hmrDownloadUpdateHandlers
4006
+ );
3773
4007
  /** @type {Map<ChunkId, string>} */
3774
- const urls = new Map();
3775
- let complete = true;
4008
+ const specifiers = new Map();
3776
4009
  for (const chunk of chunks) {
3777
4010
  if (chunk.id === null) continue;
3778
4011
  const specifier = this._getAnalyzableChunkSpecifier(
@@ -3780,18 +4013,74 @@ class RuntimeTemplate {
3780
4013
  chunk,
3781
4014
  consumingModule,
3782
4015
  chunkGraph,
3783
- undefined,
3784
4016
  consumingChunks,
3785
- sourceType
4017
+ sourceType,
4018
+ hot
3786
4019
  );
3787
- // `_getAnalyzableChunkSpecifier` has already recorded why.
3788
- if (specifier === null) {
3789
- complete = false;
4020
+ if (specifier === null) return null;
4021
+ if (
4022
+ hot &&
4023
+ !this._settledUnderHot(specifier, chunk, sourceType, consumingChunks)
4024
+ ) {
4025
+ return this._analyzableBailout(consumingModule, HOT_NAME_BAILOUT, null);
4026
+ }
4027
+ specifiers.set(chunk.id, specifier);
4028
+ }
4029
+ return specifiers.size > 0 ? specifiers : null;
4030
+ }
4031
+
4032
+ /**
4033
+ * Whether a url a hot update re-ships moves only with the runtime module's own text:
4034
+ * spelled here, or a stand-in of each asset's depth and a hash-free or settled name.
4035
+ * @param {string} specifier the specifier already quoted
4036
+ * @param {Chunk} chunk the chunk it names
4037
+ * @param {string} sourceType which asset of the chunk it names
4038
+ * @param {Chunk[]} consumingChunks the chunks the map is written into
4039
+ * @returns {boolean} true when no update moves what the fill spells
4040
+ */
4041
+ _settledUnderHot(specifier, chunk, sourceType, consumingChunks) {
4042
+ const match = ANALYZABLE_TOKEN_PAYLOAD.exec(specifier);
4043
+ if (match === null) return true;
4044
+ const parts = RuntimeTemplate._readAnalyzableSpecifier(match[1]);
4045
+ if (parts === null) return false;
4046
+ for (const [kind, value] of parts) {
4047
+ if (kind === "undo") continue;
4048
+ if (kind === "literal" && !this._hasReservedFullHash(String(value))) {
3790
4049
  continue;
3791
4050
  }
3792
- urls.set(chunk.id, `${this.importMetaUrl(specifier)}.href`);
4051
+ if (!CHUNK_SPECIFIER_PART_KINDS.has(kind)) return false;
3793
4052
  }
3794
- return urls.size > 0 ? { urls, complete } : null;
4053
+ const template = this._chunkAssetTemplate(chunk, sourceType);
4054
+ return (
4055
+ typeof template === "string" &&
4056
+ (!HASH_IN_FILENAME.test(template) ||
4057
+ this._hashedNameSettledBefore(chunk, template, consumingChunks))
4058
+ );
4059
+ }
4060
+
4061
+ /**
4062
+ * The `../` path from a chunk's hot update file, which re-runs its modules, back to
4063
+ * the output root. Hashes are neutralized; the chunk's own id may add a directory.
4064
+ * @param {Chunk} chunk the chunk being updated
4065
+ * @returns {string} the path back to the output root
4066
+ */
4067
+ _hotUpdateUndo(chunk) {
4068
+ const cached = this._hotUpdateUndoByChunk.get(chunk);
4069
+ if (cached !== undefined) return cached;
4070
+ const { outputOptions } = this;
4071
+ if (this._hotUpdateShapeText === undefined) {
4072
+ this._hotUpdateShapeText = outputOptions.hotUpdateChunkFilename.replace(
4073
+ HASH_IN_FILENAME_GLOBAL,
4074
+ "x"
4075
+ );
4076
+ }
4077
+ const undo = getUndoPath(
4078
+ this.compilation.getPath(this._hotUpdateShapeText, { chunk }),
4079
+ /** @type {string} */ (outputOptions.path),
4080
+ true
4081
+ );
4082
+ this._hotUpdateUndoByChunk.set(chunk, undo);
4083
+ return undo;
3795
4084
  }
3796
4085
 
3797
4086
  /**
@@ -3997,7 +4286,7 @@ class RuntimeTemplate {
3997
4286
  * @returns {string} the stand-in to emit
3998
4287
  */
3999
4288
  _reserveAnalyzableSpecifier(parts) {
4000
- return `./@@webpackAnalyzableChunk:${Buffer.from(JSON.stringify(parts))
4289
+ return `${ANALYZABLE_TOKEN_PREFIX}${Buffer.from(JSON.stringify(parts))
4001
4290
  .toString("base64")
4002
4291
  .replace(/\+/g, "-")
4003
4292
  .replace(/\//g, "_")
@@ -4058,16 +4347,18 @@ class RuntimeTemplate {
4058
4347
  compilation.hooks.processAssets.tapPromise(
4059
4348
  {
4060
4349
  name: PASS_NAME,
4061
- // Before source maps are written and before a minifier runs: both read
4062
- // the asset, and a stand-in is a different length than what replaces it.
4063
- // Every hash it reads is already settled — `createHash` runs ahead of
4064
- // every `processAssets` stage — and `RealContentHashPlugin` still repairs
4065
- // the names afterwards.
4350
+ // Before source maps are written and before a minifier runs, since both
4351
+ // read the asset and a stand-in differs in length from what replaces it.
4352
+ // Every hash it reads is settled: `createHash` precedes every stage.
4066
4353
  stage: getCompilation().PROCESS_ASSETS_STAGE_DERIVED
4067
4354
  },
4068
4355
  async () => {
4069
4356
  const { outputOptions } = compilation;
4070
4357
  const fullHash = compilation.hash;
4358
+ // The assets a stand-in landed in whose hashed name has to be brought
4359
+ // back in line, which `RealContentHashPlugin` then does.
4360
+ /** @type {Set<string>} */
4361
+ const repairedAssets = new Set();
4071
4362
  /** @type {Map<string, Chunk> | undefined} */
4072
4363
  let chunksById;
4073
4364
  /** @type {Map<string, Chunk> | undefined} */
@@ -4122,7 +4413,9 @@ class RuntimeTemplate {
4122
4413
  let base;
4123
4414
  let specifier = "";
4124
4415
  for (const [kind, value] of parts) {
4125
- if (kind === "base") {
4416
+ if (kind === "repair") {
4417
+ repairedAssets.add(assetName);
4418
+ } else if (kind === "base") {
4126
4419
  base = /** @type {string} */ (value);
4127
4420
  } else if (kind === "literal") {
4128
4421
  specifier += value;
@@ -4193,7 +4486,7 @@ class RuntimeTemplate {
4193
4486
  // the chunk loader does. A literal part may still carry a stand-in of its own,
4194
4487
  // so finish those here rather than scanning again.
4195
4488
  return fillFullHash(
4196
- /^(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(specifier)
4489
+ RESOLVABLE_SPECIFIER_REGEXP.test(specifier)
4197
4490
  ? specifier
4198
4491
  : `./${specifier}`
4199
4492
  );
@@ -4246,6 +4539,8 @@ class RuntimeTemplate {
4246
4539
 
4247
4540
  tasks.push({ name, source, replacements });
4248
4541
  }
4542
+ compilation.runtimeTemplate._analyzableRepairedAssets =
4543
+ repairedAssets;
4249
4544
  if (tasks.length === 0) return;
4250
4545
 
4251
4546
  await Promise.all(