@depup/webpack 5.109.2-depup.0 → 5.110.3-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 (647) hide show
  1. package/README.md +5 -5
  2. package/changes.json +7 -7
  3. package/lib/APIPlugin.js +123 -17
  4. package/lib/AsyncDependenciesBlock.js +10 -7
  5. package/lib/AutomaticPrefetchPlugin.js +1 -1
  6. package/lib/BannerPlugin.js +10 -6
  7. package/lib/CacheFacade.js +6 -6
  8. package/lib/Chunk.js +14 -11
  9. package/lib/ChunkGraph.js +46 -35
  10. package/lib/ChunkGroup.js +7 -7
  11. package/lib/ChunkTemplate.js +35 -44
  12. package/lib/CircularModulesPlugin.js +205 -28
  13. package/lib/CleanPlugin.js +4 -7
  14. package/lib/CodeGenerationResults.js +11 -8
  15. package/lib/CompatibilityPlugin.js +7 -7
  16. package/lib/Compilation.js +688 -409
  17. package/lib/Compiler.js +53 -38
  18. package/lib/ConcatenationScope.js +107 -8
  19. package/lib/ConditionalInitFragment.js +3 -3
  20. package/lib/ConstPlugin.js +13 -11
  21. package/lib/ContextExclusionPlugin.js +1 -1
  22. package/lib/ContextModule.js +146 -54
  23. package/lib/ContextModuleFactory.js +46 -14
  24. package/lib/ContextReplacementPlugin.js +12 -14
  25. package/lib/DefinePlugin.js +121 -37
  26. package/lib/DependenciesBlock.js +9 -6
  27. package/lib/Dependency.js +36 -16
  28. package/lib/DependencyTemplate.js +11 -12
  29. package/lib/DependencyTemplates.js +3 -3
  30. package/lib/DotenvPlugin.js +91 -26
  31. package/lib/DynamicEntryPlugin.js +8 -4
  32. package/lib/EntryOptionPlugin.js +8 -4
  33. package/lib/EntryPlugin.js +2 -2
  34. package/lib/Entrypoint.js +6 -2
  35. package/lib/EnvironmentPlugin.js +2 -2
  36. package/lib/EvalDevToolModulePlugin.js +8 -4
  37. package/lib/EvalSourceMapDevToolPlugin.js +15 -8
  38. package/lib/ExportsInfo.js +111 -14
  39. package/lib/ExportsInfoApiPlugin.js +2 -4
  40. package/lib/ExternalModule.js +232 -77
  41. package/lib/ExternalModuleFactoryPlugin.js +97 -38
  42. package/lib/ExternalsPlugin.js +10 -6
  43. package/lib/FileSystemInfo.js +44 -70
  44. package/lib/FlagAllModulesAsUsedPlugin.js +2 -3
  45. package/lib/FlagDependencyExportsPlugin.js +76 -19
  46. package/lib/FlagDependencyUsagePlugin.js +40 -49
  47. package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
  48. package/lib/Generator.js +36 -15
  49. package/lib/HotModuleReplacementPlugin.js +16 -44
  50. package/lib/IgnorePlugin.js +8 -4
  51. package/lib/IgnoreWarningsPlugin.js +2 -2
  52. package/lib/InitFragment.js +8 -4
  53. package/lib/JavascriptMetaInfoPlugin.js +35 -4
  54. package/lib/LazyBarrel.js +3 -4
  55. package/lib/LibraryTemplatePlugin.js +10 -6
  56. package/lib/LoaderOptionsPlugin.js +7 -3
  57. package/lib/LoaderTargetPlugin.js +1 -1
  58. package/lib/MainTemplate.js +49 -42
  59. package/lib/ManifestPlugin.js +12 -11
  60. package/lib/Module.js +62 -33
  61. package/lib/ModuleFactory.js +3 -3
  62. package/lib/ModuleFilenameHelpers.js +9 -4
  63. package/lib/ModuleGraph.js +195 -21
  64. package/lib/ModuleGraphConnection.js +6 -13
  65. package/lib/ModuleInfoHeaderPlugin.js +8 -10
  66. package/lib/ModuleTemplate.js +62 -63
  67. package/lib/MultiCompiler.js +130 -64
  68. package/lib/MultiStats.js +40 -9
  69. package/lib/MultiWatching.js +3 -3
  70. package/lib/NoEmitOnErrorsPlugin.js +1 -1
  71. package/lib/NodeStuffPlugin.js +29 -19
  72. package/lib/NormalModule.js +152 -103
  73. package/lib/NormalModuleFactory.js +555 -110
  74. package/lib/NormalModuleReplacementPlugin.js +5 -8
  75. package/lib/NullFactory.js +6 -2
  76. package/lib/OptionsApply.js +7 -3
  77. package/lib/Parser.js +7 -3
  78. package/lib/PlatformPlugin.js +2 -2
  79. package/lib/PrefetchPlugin.js +1 -1
  80. package/lib/ProgressPlugin.js +16 -13
  81. package/lib/ProvidePlugin.js +3 -5
  82. package/lib/RawModule.js +25 -17
  83. package/lib/RecordIdsPlugin.js +3 -3
  84. package/lib/RequestShortener.js +1 -1
  85. package/lib/ResolverFactory.js +2 -2
  86. package/lib/RuntimeGlobals.js +22 -10
  87. package/lib/RuntimeModule.js +29 -19
  88. package/lib/RuntimePlugin.js +335 -169
  89. package/lib/RuntimeTemplate.js +2761 -316
  90. package/lib/SelfModuleFactory.js +7 -3
  91. package/lib/SourceMapDevToolModuleOptionsPlugin.js +6 -2
  92. package/lib/SourceMapDevToolPlugin.js +30 -20
  93. package/lib/Stats.js +3 -4
  94. package/lib/Template.js +32 -22
  95. package/lib/TemplatedPathPlugin.js +96 -14
  96. package/lib/UseStrictPlugin.js +4 -6
  97. package/lib/WarnCaseSensitiveModulesPlugin.js +4 -4
  98. package/lib/WarnDeprecatedOptionPlugin.js +1 -1
  99. package/lib/WarnNoModeSetPlugin.js +1 -1
  100. package/lib/WatchIgnorePlugin.js +8 -6
  101. package/lib/Watching.js +8 -8
  102. package/lib/WebpackIsIncludedPlugin.js +2 -4
  103. package/lib/WebpackOptionsApply.js +308 -18
  104. package/lib/WebpackOptionsDefaulter.js +6 -2
  105. package/lib/asset/AssetBytesGenerator.js +12 -10
  106. package/lib/asset/AssetBytesParser.js +2 -4
  107. package/lib/asset/AssetGenerator.js +188 -95
  108. package/lib/asset/AssetModule.js +7 -3
  109. package/lib/asset/AssetModulesPlugin.js +110 -38
  110. package/lib/asset/AssetParser.js +9 -7
  111. package/lib/asset/AssetSourceGenerator.js +60 -13
  112. package/lib/asset/AssetSourceParser.js +2 -4
  113. package/lib/asset/RawDataUrlModule.js +24 -16
  114. package/lib/asset/WebManifestGenerator.js +8 -10
  115. package/lib/asset/WebManifestParser.js +24 -10
  116. package/lib/async-modules/AsyncModuleHelpers.js +12 -6
  117. package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
  118. package/lib/async-modules/InferAsyncModulesPlugin.js +2 -2
  119. package/lib/async-modules/isGeneratorLowered.js +4 -4
  120. package/lib/buildChunkGraph.js +36 -27
  121. package/lib/bun/BunTargetPlugin.js +1 -1
  122. package/lib/cache/AddBuildDependenciesPlugin.js +1 -1
  123. package/lib/cache/AddManagedPathsPlugin.js +1 -1
  124. package/lib/cache/IdleFileCachePlugin.js +2 -2
  125. package/lib/cache/MemoryCachePlugin.js +18 -10
  126. package/lib/cache/MemoryWithGcCachePlugin.js +34 -22
  127. package/lib/cache/PackFileCacheStrategy.js +30 -23
  128. package/lib/cache/ResolverCachePlugin.js +38 -18
  129. package/lib/cache/getLazyHashedEtag.js +1 -2
  130. package/lib/cache/mergeEtags.js +1 -1
  131. package/lib/cli.js +1 -3
  132. package/lib/config/browserslistTargetHandler.js +41 -5
  133. package/lib/config/defaults.js +270 -78
  134. package/lib/config/defineConfig.js +10 -2
  135. package/lib/config/getClaimedAssetTypes.js +65 -0
  136. package/lib/config/normalization.js +46 -16
  137. package/lib/config/target.js +46 -3
  138. package/lib/container/ContainerEntryDependency.js +1 -1
  139. package/lib/container/ContainerEntryModule.js +24 -15
  140. package/lib/container/ContainerEntryModuleFactory.js +7 -3
  141. package/lib/container/ContainerPlugin.js +9 -10
  142. package/lib/container/ContainerReferencePlugin.js +6 -2
  143. package/lib/container/FallbackDependency.js +1 -1
  144. package/lib/container/FallbackModule.js +24 -17
  145. package/lib/container/FallbackModuleFactory.js +7 -3
  146. package/lib/container/HoistContainerReferencesPlugin.js +6 -11
  147. package/lib/container/ModuleFederationPlugin.js +7 -24
  148. package/lib/container/RemoteModule.js +27 -19
  149. package/lib/container/RemoteRuntimeModule.js +10 -8
  150. package/lib/container/moduleFederationHooks.js +32 -0
  151. package/lib/css/CssGenerator.js +171 -43
  152. package/lib/css/CssInjectStyleRuntimeModule.js +7 -5
  153. package/lib/css/CssLoadingRuntimeModule.js +84 -32
  154. package/lib/css/CssModule.js +10 -7
  155. package/lib/css/CssModulesPlugin.js +172 -100
  156. package/lib/css/CssParser.js +1113 -568
  157. package/lib/css/CssServerStylesRuntimeModule.js +54 -0
  158. package/lib/css/cssMinify.js +168 -0
  159. package/lib/css/data.js +5334 -0
  160. package/lib/css/syntax.js +9647 -232
  161. package/lib/debug/ProfilingPlugin.js +14 -9
  162. package/lib/deno/DenoTargetPlugin.js +1 -1
  163. package/lib/dependencies/AMDDefineDependency.js +112 -87
  164. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +30 -17
  165. package/lib/dependencies/AMDPlugin.js +9 -7
  166. package/lib/dependencies/AMDRequireArrayDependency.js +5 -5
  167. package/lib/dependencies/AMDRequireContextDependency.js +2 -2
  168. package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -1
  169. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +25 -14
  170. package/lib/dependencies/AMDRequireDependency.js +8 -7
  171. package/lib/dependencies/AMDRequireItemDependency.js +1 -1
  172. package/lib/dependencies/AMDRuntimeModules.js +21 -1
  173. package/lib/dependencies/BuildTimeConstDependency.js +102 -0
  174. package/lib/dependencies/CachedConstDependency.js +11 -8
  175. package/lib/dependencies/CommonJsDependencyHelpers.js +67 -46
  176. package/lib/dependencies/CommonJsExportRequireDependency.js +121 -45
  177. package/lib/dependencies/CommonJsExportsDependency.js +53 -49
  178. package/lib/dependencies/CommonJsExportsParserPlugin.js +207 -25
  179. package/lib/dependencies/CommonJsFullRequireDependency.js +119 -34
  180. package/lib/dependencies/CommonJsImportsParserPlugin.js +100 -50
  181. package/lib/dependencies/CommonJsObjectExportDependency.js +188 -0
  182. package/lib/dependencies/CommonJsPlugin.js +35 -6
  183. package/lib/dependencies/CommonJsRequireContextDependency.js +5 -6
  184. package/lib/dependencies/CommonJsRequireDependency.js +170 -27
  185. package/lib/dependencies/CommonJsSelfReferenceDependency.js +63 -38
  186. package/lib/dependencies/ConstDependency.js +8 -9
  187. package/lib/dependencies/ContextDependency.js +12 -8
  188. package/lib/dependencies/ContextDependencyHelpers.js +14 -9
  189. package/lib/dependencies/ContextDependencyTemplateAsId.js +4 -4
  190. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +24 -11
  191. package/lib/dependencies/ContextElementDependency.js +31 -12
  192. package/lib/dependencies/CreateRequireParserPlugin.js +12 -7
  193. package/lib/dependencies/CreateScriptUrlDependency.js +4 -4
  194. package/lib/dependencies/CssIcssExportDependency.js +56 -28
  195. package/lib/dependencies/CssIcssImportDependency.js +17 -13
  196. package/lib/dependencies/CssIcssSymbolDependency.js +9 -10
  197. package/lib/dependencies/CssImportDependency.js +18 -9
  198. package/lib/dependencies/CssUrlDependency.js +17 -13
  199. package/lib/dependencies/DllEntryDependency.js +1 -1
  200. package/lib/dependencies/DynamicExports.js +2 -2
  201. package/lib/dependencies/ExportBindingInitFragment.js +36 -9
  202. package/lib/dependencies/ExportsInfoDependency.js +7 -8
  203. package/lib/dependencies/ExternalModuleDependency.js +9 -5
  204. package/lib/dependencies/ExternalModuleInitFragment.js +2 -2
  205. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +8 -5
  206. package/lib/dependencies/HarmonyAcceptDependency.js +5 -5
  207. package/lib/dependencies/HarmonyCompatibilityDependency.js +52 -17
  208. package/lib/dependencies/HarmonyDetectionParserPlugin.js +11 -7
  209. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +23 -14
  210. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +80 -12
  211. package/lib/dependencies/HarmonyExportExpressionDependency.js +23 -18
  212. package/lib/dependencies/HarmonyExportHeaderDependency.js +7 -7
  213. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +286 -80
  214. package/lib/dependencies/HarmonyExportInitFragment.js +18 -6
  215. package/lib/dependencies/HarmonyExportSpecifierDependency.js +51 -14
  216. package/lib/dependencies/HarmonyExports.js +7 -4
  217. package/lib/dependencies/HarmonyImportDependency.js +121 -60
  218. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +124 -38
  219. package/lib/dependencies/HarmonyImportGuard.js +20 -30
  220. package/lib/dependencies/HarmonyImportSideEffectDependency.js +152 -9
  221. package/lib/dependencies/HarmonyImportSpecifierDependency.js +97 -49
  222. package/lib/dependencies/HarmonyModulesPlugin.js +7 -3
  223. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -3
  224. package/lib/dependencies/HtmlEntryDependency.js +49 -31
  225. package/lib/dependencies/HtmlInlineHtmlDependency.js +7 -8
  226. package/lib/dependencies/HtmlInlineScriptDependency.js +11 -8
  227. package/lib/dependencies/HtmlInlineStyleDependency.js +7 -10
  228. package/lib/dependencies/HtmlSourceDependency.js +22 -14
  229. package/lib/dependencies/ImportContextDependency.js +45 -5
  230. package/lib/dependencies/ImportDependency.js +33 -50
  231. package/lib/dependencies/ImportEagerDependency.js +6 -9
  232. package/lib/dependencies/ImportMetaContextDependency.js +2 -2
  233. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +14 -13
  234. package/lib/dependencies/ImportMetaContextPlugin.js +7 -3
  235. package/lib/dependencies/ImportMetaGlobDependency.js +2 -2
  236. package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +2 -3
  237. package/lib/dependencies/ImportMetaGlobHelpers.js +19 -22
  238. package/lib/dependencies/ImportMetaHotAcceptDependency.js +1 -1
  239. package/lib/dependencies/ImportMetaHotDeclineDependency.js +1 -1
  240. package/lib/dependencies/ImportMetaPlugin.js +154 -71
  241. package/lib/dependencies/ImportMetaResolveDependency.js +3 -4
  242. package/lib/dependencies/ImportParserPlugin.js +73 -49
  243. package/lib/dependencies/ImportPhase.js +12 -5
  244. package/lib/dependencies/ImportPlugin.js +7 -3
  245. package/lib/dependencies/ImportWeakDependency.js +6 -9
  246. package/lib/dependencies/JsonExportsDependency.js +11 -7
  247. package/lib/dependencies/LoaderDependency.js +2 -2
  248. package/lib/dependencies/LoaderImportDependency.js +2 -2
  249. package/lib/dependencies/LoaderPlugin.js +11 -7
  250. package/lib/dependencies/LocalModuleDependency.js +5 -5
  251. package/lib/dependencies/LocalModulesHelpers.js +1 -1
  252. package/lib/dependencies/ModuleDecoratorDependency.js +6 -7
  253. package/lib/dependencies/ModuleDependency.js +9 -6
  254. package/lib/dependencies/ModuleDependencyTemplateAsId.js +4 -4
  255. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +3 -3
  256. package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
  257. package/lib/dependencies/ModuleHotDeclineDependency.js +1 -1
  258. package/lib/dependencies/ModuleInitFragmentDependency.js +24 -10
  259. package/lib/dependencies/NullDependency.js +3 -3
  260. package/lib/dependencies/ProvidedDependency.js +14 -10
  261. package/lib/dependencies/PureExpressionDependency.js +9 -10
  262. package/lib/dependencies/RequireContextDependency.js +2 -2
  263. package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -4
  264. package/lib/dependencies/RequireContextPlugin.js +8 -4
  265. package/lib/dependencies/RequireEnsureDependenciesBlock.js +2 -2
  266. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +5 -8
  267. package/lib/dependencies/RequireEnsureDependency.js +8 -7
  268. package/lib/dependencies/RequireEnsurePlugin.js +7 -3
  269. package/lib/dependencies/RequireHeaderDependency.js +50 -12
  270. package/lib/dependencies/RequireIncludeDependency.js +6 -6
  271. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +2 -3
  272. package/lib/dependencies/RequireIncludePlugin.js +7 -3
  273. package/lib/dependencies/RequireJsStuffPlugin.js +7 -3
  274. package/lib/dependencies/RequireResolveContextDependency.js +2 -2
  275. package/lib/dependencies/RequireResolveDependency.js +4 -4
  276. package/lib/dependencies/RequireResolveHeaderDependency.js +4 -4
  277. package/lib/dependencies/RuntimeRequirementsDependency.js +5 -6
  278. package/lib/dependencies/StaticExportsDependency.js +2 -2
  279. package/lib/dependencies/SystemPlugin.js +10 -6
  280. package/lib/dependencies/SystemRuntimeModule.js +10 -0
  281. package/lib/dependencies/TopLevelAwaitDependency.js +11 -7
  282. package/lib/dependencies/URLContextDependency.js +2 -2
  283. package/lib/dependencies/URLDependency.js +110 -64
  284. package/lib/dependencies/URLPlugin.js +7 -3
  285. package/lib/dependencies/UnsupportedDependency.js +4 -4
  286. package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -4
  287. package/lib/dependencies/WebAssemblyImportDependency.js +5 -5
  288. package/lib/dependencies/WebpackIsIncludedDependency.js +6 -6
  289. package/lib/dependencies/WorkerAndWorkletPlugin.js +47 -28
  290. package/lib/dependencies/WorkerDependency.js +22 -22
  291. package/lib/dependencies/WorkletDependency.js +18 -21
  292. package/lib/dependencies/getFunctionExpression.js +8 -4
  293. package/lib/dependencies/importOptionsCheck.js +47 -0
  294. package/lib/dependencies/processExportInfo.js +5 -5
  295. package/lib/dll/DelegatedModule.js +34 -22
  296. package/lib/dll/DelegatedModuleFactoryPlugin.js +15 -7
  297. package/lib/dll/DelegatedPlugin.js +2 -2
  298. package/lib/dll/DllEntryPlugin.js +2 -2
  299. package/lib/dll/DllModule.js +22 -15
  300. package/lib/dll/DllModuleFactory.js +7 -3
  301. package/lib/dll/DllPlugin.js +7 -5
  302. package/lib/dll/DllReferencePlugin.js +10 -7
  303. package/lib/dll/LibManifestPlugin.js +5 -5
  304. package/lib/electron/ElectronTargetPlugin.js +53 -49
  305. package/lib/errors/AsyncChunkWaterfallWarning.js +36 -0
  306. package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
  307. package/lib/errors/BroadContextsWarning.js +43 -0
  308. package/lib/errors/BuildCycleError.js +1 -1
  309. package/lib/errors/CacheEffectivenessWarning.js +55 -0
  310. package/lib/errors/ChunkRenderError.js +1 -1
  311. package/lib/errors/CircularDependenciesWarning.js +38 -0
  312. package/lib/errors/CodeGenerationError.js +1 -1
  313. package/lib/errors/CommentCompilationWarning.js +1 -1
  314. package/lib/errors/ConflictingResourceHintsWarning.js +35 -0
  315. package/lib/errors/DotenvFileError.js +29 -0
  316. package/lib/errors/DuplicateModulesWarning.js +45 -0
  317. package/lib/errors/DynamicExportsWarning.js +30 -0
  318. package/lib/errors/EmbeddedSourceMapsWarning.js +25 -0
  319. package/lib/errors/EntrypointOverlapWarning.js +45 -0
  320. package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
  321. package/lib/errors/EvalUsageWarning.js +28 -0
  322. package/lib/errors/HookWebpackError.js +5 -5
  323. package/lib/errors/HotspotsWarning.js +57 -0
  324. package/lib/errors/IgnoreErrorModuleFactory.js +7 -3
  325. package/lib/errors/ImportedBindingAssignmentError.js +30 -0
  326. package/lib/errors/InlinedAssetsWarning.js +36 -0
  327. package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
  328. package/lib/errors/LargeModulesWarning.js +45 -0
  329. package/lib/errors/LegacyJavascriptWarning.js +48 -0
  330. package/lib/errors/MissingSideEffectsWarning.js +36 -0
  331. package/lib/errors/MixedExportsWarning.js +41 -0
  332. package/lib/errors/ModuleDependencyError.js +13 -16
  333. package/lib/errors/ModuleDependencyWarning.js +5 -15
  334. package/lib/errors/ModuleHashingError.js +1 -1
  335. package/lib/errors/ModuleNotFoundError.js +2 -2
  336. package/lib/errors/ModuleParseError.js +1 -2
  337. package/lib/errors/ModuleRestoreError.js +1 -1
  338. package/lib/errors/ModuleStoreError.js +1 -1
  339. package/lib/errors/NodeStuffInWebError.js +1 -1
  340. package/lib/errors/OsDependentRuleWarning.js +31 -0
  341. package/lib/errors/PureAnnotationsWarning.js +36 -0
  342. package/lib/errors/RedundantDynamicImportWarning.js +31 -0
  343. package/lib/errors/ScopeHoistingBailoutsWarning.js +41 -0
  344. package/lib/errors/SplitChunksCappedWarning.js +41 -0
  345. package/lib/errors/TinyChunksWarning.js +40 -0
  346. package/lib/errors/TopLevelThisWarning.js +34 -0
  347. package/lib/errors/UnsplitVendorsWarning.js +42 -0
  348. package/lib/errors/UnsupportedFeatureWarning.js +1 -1
  349. package/lib/errors/UnusedAliasesWarning.js +29 -0
  350. package/lib/errors/UnusedDefinesWarning.js +29 -0
  351. package/lib/errors/UnusedExternalsWarning.js +29 -0
  352. package/lib/errors/UnusedReexportsWarning.js +42 -0
  353. package/lib/errors/UnusedRuleWarning.js +29 -0
  354. package/lib/errors/WebpackError.js +9 -5
  355. package/lib/errors/deriveStackFromNestedError.js +90 -0
  356. package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
  357. package/lib/esm/ModuleChunkFormatPlugin.js +37 -19
  358. package/lib/esm/ModuleChunkLoadingPlugin.js +86 -51
  359. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +161 -62
  360. package/lib/hmr/HotModuleReplacement.runtime.js +24 -5
  361. package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
  362. package/lib/hmr/LazyCompilationPlugin.js +45 -24
  363. package/lib/hmr/lazyCompilationBackend.js +9 -6
  364. package/lib/hmr/parserHooks.js +56 -0
  365. package/lib/html/HtmlGenerator.js +277 -77
  366. package/lib/html/HtmlModule.js +7 -3
  367. package/lib/html/HtmlModulesPlugin.js +366 -200
  368. package/lib/html/HtmlParser.js +31 -86
  369. package/lib/html/data.js +1928 -0
  370. package/lib/html/htmlMinify.js +288 -0
  371. package/lib/html/syntax.js +6034 -1384
  372. package/lib/ids/ChunkModuleIdRangePlugin.js +3 -3
  373. package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
  374. package/lib/ids/DeterministicModuleIdsPlugin.js +2 -2
  375. package/lib/ids/HashedModuleIdsPlugin.js +6 -2
  376. package/lib/ids/IdHelpers.js +7 -8
  377. package/lib/ids/NamedChunkIdsPlugin.js +1 -1
  378. package/lib/ids/NamedModuleIdsPlugin.js +1 -1
  379. package/lib/ids/NaturalChunkIdsPlugin.js +2 -2
  380. package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
  381. package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -3
  382. package/lib/ids/OccurrenceModuleIdsPlugin.js +7 -3
  383. package/lib/ids/SyncModuleIdsPlugin.js +4 -4
  384. package/lib/index.js +10 -0
  385. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +3 -3
  386. package/lib/javascript/BasicEvaluatedExpression.js +18 -14
  387. package/lib/javascript/ChunkFormatHelpers.js +6 -6
  388. package/lib/javascript/ChunkHelpers.js +1 -1
  389. package/lib/javascript/CommonJsChunkFormatPlugin.js +11 -5
  390. package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
  391. package/lib/javascript/JavascriptGenerator.js +65 -165
  392. package/lib/javascript/JavascriptModule.js +9 -3
  393. package/lib/javascript/JavascriptModulesPlugin.js +103 -123
  394. package/lib/javascript/JavascriptParser.js +242 -99
  395. package/lib/javascript/JavascriptParserHelpers.js +10 -7
  396. package/lib/javascript/ScopeAnalyzer.js +1094 -0
  397. package/lib/javascript/StartupHelpers.js +55 -9
  398. package/lib/javascript/syntax.js +2678 -232
  399. package/lib/json/JsonData.js +8 -4
  400. package/lib/json/JsonGenerator.js +38 -16
  401. package/lib/json/JsonModule.js +7 -3
  402. package/lib/json/JsonModulesPlugin.js +1 -1
  403. package/lib/json/JsonParser.js +5 -6
  404. package/lib/library/AbstractLibraryPlugin.js +20 -14
  405. package/lib/library/AmdLibraryPlugin.js +11 -7
  406. package/lib/library/AssignLibraryPlugin.js +19 -13
  407. package/lib/library/EnableLibraryPlugin.js +2 -2
  408. package/lib/library/ExportPropertyLibraryPlugin.js +15 -8
  409. package/lib/library/JsonpLibraryPlugin.js +11 -7
  410. package/lib/library/ModuleLibraryPlugin.js +256 -64
  411. package/lib/library/SystemLibraryPlugin.js +12 -8
  412. package/lib/library/UmdLibraryPlugin.js +62 -25
  413. package/lib/loaders/LoaderRunner.js +47 -6
  414. package/lib/loaders/loadLoader.js +8 -4
  415. package/lib/logging/createConsoleLogger.js +7 -4
  416. package/lib/node/CommonJsChunkLoadingPlugin.js +36 -22
  417. package/lib/node/NodeEnvironmentPlugin.js +17 -3
  418. package/lib/node/NodeSourcePlugin.js +1 -1
  419. package/lib/node/NodeTargetPlugin.js +4 -3
  420. package/lib/node/NodeTemplatePlugin.js +1 -1
  421. package/lib/node/NodeWatchFileSystem.js +70 -9
  422. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +35 -38
  423. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +65 -19
  424. package/lib/node/ReadFileCompileWasmPlugin.js +28 -16
  425. package/lib/node/RequireChunkLoadingRuntimeModule.js +35 -38
  426. package/lib/node/nodeConsole.js +7 -3
  427. package/lib/optimize/AggressiveMergingPlugin.js +2 -2
  428. package/lib/optimize/AggressiveSplittingPlugin.js +9 -6
  429. package/lib/optimize/ConcatenatedModule.js +1030 -476
  430. package/lib/optimize/ConstExportsPlugin.js +16 -7
  431. package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
  432. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -4
  433. package/lib/optimize/InlineExports.js +130 -5
  434. package/lib/optimize/InnerGraph.js +28 -12
  435. package/lib/optimize/InnerGraphPlugin.js +23 -18
  436. package/lib/optimize/LimitChunkCountPlugin.js +7 -3
  437. package/lib/optimize/MangleExportsPlugin.js +7 -8
  438. package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -3
  439. package/lib/optimize/MinChunkSizePlugin.js +7 -3
  440. package/lib/optimize/ModuleConcatenationPlugin.js +51 -35
  441. package/lib/optimize/RealContentHashPlugin.js +121 -41
  442. package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
  443. package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
  444. package/lib/optimize/RuntimeChunkPlugin.js +2 -2
  445. package/lib/optimize/SideEffectsFlagPlugin.js +262 -39
  446. package/lib/optimize/SplitChunksPlugin.js +86 -24
  447. package/lib/performance/AssetsOverSizeLimitWarning.js +10 -2
  448. package/lib/performance/AsyncChunkWaterfallsPlugin.js +136 -0
  449. package/lib/performance/BroadContextsPlugin.js +142 -0
  450. package/lib/performance/CacheEffectivenessPlugin.js +125 -0
  451. package/lib/performance/ConflictingResourceHintsPlugin.js +99 -0
  452. package/lib/performance/DuplicateModulesPlugin.js +93 -0
  453. package/lib/performance/DuplicatePackagesPlugin.js +119 -0
  454. package/lib/performance/DuplicatePackagesWarning.js +84 -0
  455. package/lib/performance/DynamicExportsPlugin.js +120 -0
  456. package/lib/performance/EmbeddedSourceMapsPlugin.js +71 -0
  457. package/lib/performance/EntrypointOverlapPlugin.js +122 -0
  458. package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -1
  459. package/lib/performance/EvalUsagePlugin.js +115 -0
  460. package/lib/performance/HotspotsPlugin.js +296 -0
  461. package/lib/performance/InlinedAssetsPlugin.js +99 -0
  462. package/lib/performance/LargeModulesPlugin.js +126 -0
  463. package/lib/performance/LegacyJavascriptPlugin.js +139 -0
  464. package/lib/performance/MissingSideEffectsPlugin.js +138 -0
  465. package/lib/performance/MixedExportsPlugin.js +136 -0
  466. package/lib/performance/OsDependentRuleWarningPlugin.js +178 -0
  467. package/lib/performance/PureAnnotationsPlugin.js +219 -0
  468. package/lib/performance/RedundantDynamicImportsPlugin.js +225 -0
  469. package/lib/performance/RuntimeInLargeChunkWarning.js +27 -0
  470. package/lib/performance/ScopeHoistingBailoutsPlugin.js +164 -0
  471. package/lib/performance/SizeLimitsPlugin.js +139 -7
  472. package/lib/performance/SplitChunksCappedPlugin.js +99 -0
  473. package/lib/performance/TinyChunksPlugin.js +128 -0
  474. package/lib/performance/TopLevelThisPlugin.js +208 -0
  475. package/lib/performance/UnsplitVendorsPlugin.js +112 -0
  476. package/lib/performance/UnusedAliasesPlugin.js +253 -0
  477. package/lib/performance/UnusedDefinesPlugin.js +87 -0
  478. package/lib/performance/UnusedExternalsPlugin.js +110 -0
  479. package/lib/performance/UnusedReexportsPlugin.js +159 -0
  480. package/lib/performance/UnusedRuleWarningPlugin.js +105 -0
  481. package/lib/performance/getModuleSize.js +22 -0
  482. package/lib/performance/getSourceModules.js +22 -0
  483. package/lib/performance/hasOnlyUnusedExports.js +40 -0
  484. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +24 -10
  485. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +63 -46
  486. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +2 -3
  487. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
  488. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
  489. package/lib/prefetch/ResourceHintPlugin.js +295 -79
  490. package/lib/prefetch/ResourceHintRuntimeModule.js +1 -21
  491. package/lib/prefetch/StartupAssetHintRuntimeModule.js +10 -133
  492. package/lib/prefetch/parseResourceHintOptions.js +31 -4
  493. package/lib/rules/BasicEffectRulePlugin.js +2 -2
  494. package/lib/rules/BasicMatcherRulePlugin.js +8 -4
  495. package/lib/rules/GlobMatcherRulePlugin.js +68 -0
  496. package/lib/rules/ObjectMatcherRulePlugin.js +12 -5
  497. package/lib/rules/RuleSetCompiler.js +146 -12
  498. package/lib/rules/UseEffectRulePlugin.js +18 -11
  499. package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +11 -1
  500. package/lib/runtime/AsyncModuleRuntimeModule.js +6 -2
  501. package/lib/runtime/AutoPublicPathRuntimeModule.js +15 -20
  502. package/lib/runtime/BaseUriRuntimeModule.js +33 -7
  503. package/lib/runtime/ChunkNameRuntimeModule.js +10 -0
  504. package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +11 -1
  505. package/lib/runtime/CompatRuntimeModule.js +5 -3
  506. package/lib/runtime/ConcatenationWrapRuntimeModule.js +90 -0
  507. package/lib/runtime/ConstructRequireRuntimeModule.js +52 -0
  508. package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +8 -6
  509. package/lib/runtime/CreateScriptRuntimeModule.js +11 -1
  510. package/lib/runtime/CreateScriptUrlRuntimeModule.js +11 -1
  511. package/lib/runtime/DefinePropertyGettersRuntimeModule.js +56 -38
  512. package/lib/runtime/EnsureChunkRuntimeModule.js +18 -2
  513. package/lib/runtime/GetChunkFilenameRuntimeModule.js +62 -37
  514. package/lib/runtime/GetFullHashRuntimeModule.js +12 -2
  515. package/lib/runtime/GetMainFilenameRuntimeModule.js +12 -2
  516. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -2
  517. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +16 -3
  518. package/lib/runtime/GlobalRuntimeModule.js +18 -0
  519. package/lib/runtime/HasOwnPropertyRuntimeModule.js +12 -2
  520. package/lib/runtime/LoadScriptRuntimeModule.js +2 -2
  521. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +34 -7
  522. package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +22 -6
  523. package/lib/runtime/NonceRuntimeModule.js +10 -0
  524. package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -3
  525. package/lib/runtime/PublicPathRuntimeModule.js +12 -2
  526. package/lib/runtime/RelativeUrlRuntimeModule.js +11 -1
  527. package/lib/runtime/RuntimeIdRuntimeModule.js +12 -2
  528. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +11 -1
  529. package/lib/runtime/StartupChunkDependenciesPlugin.js +18 -9
  530. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +3 -3
  531. package/lib/runtime/StartupEntrypointRuntimeModule.js +21 -4
  532. package/lib/runtime/SystemContextRuntimeModule.js +10 -0
  533. package/lib/runtime/ToBinaryRuntimeModule.js +1 -1
  534. package/lib/runtime/WorkerRuntimeModule.js +11 -1
  535. package/lib/runtime/baseUri.js +63 -0
  536. package/lib/schemes/DataUriPlugin.js +1 -1
  537. package/lib/schemes/FileUriPlugin.js +1 -1
  538. package/lib/schemes/HttpUriPlugin.js +46 -20
  539. package/lib/schemes/VirtualUrlPlugin.js +13 -7
  540. package/lib/serialization/AggregateErrorSerializer.js +1 -1
  541. package/lib/serialization/BinaryMiddleware.js +4 -4
  542. package/lib/serialization/ErrorObjectSerializer.js +1 -1
  543. package/lib/serialization/FileMiddleware.js +22 -9
  544. package/lib/serialization/ObjectMiddleware.js +139 -114
  545. package/lib/serialization/PlainObjectSerializer.js +19 -16
  546. package/lib/sharing/ConsumeSharedModule.js +30 -21
  547. package/lib/sharing/ConsumeSharedPlugin.js +18 -10
  548. package/lib/sharing/ConsumeSharedRuntimeModule.js +6 -9
  549. package/lib/sharing/ProvideSharedModule.js +25 -16
  550. package/lib/sharing/ProvideSharedModuleFactory.js +7 -3
  551. package/lib/sharing/ProvideSharedPlugin.js +8 -4
  552. package/lib/sharing/SharePlugin.js +17 -5
  553. package/lib/sharing/ShareRuntimeModule.js +4 -4
  554. package/lib/sharing/resolveMatchedConfigs.js +9 -6
  555. package/lib/sharing/utils.js +1 -3
  556. package/lib/stats/DefaultStatsFactoryPlugin.js +50 -29
  557. package/lib/stats/DefaultStatsPresetPlugin.js +17 -8
  558. package/lib/stats/DefaultStatsPrinterPlugin.js +36 -26
  559. package/lib/stats/StatsFactory.js +25 -26
  560. package/lib/stats/StatsPrinter.js +16 -12
  561. package/lib/typescript/TypeScriptPlugin.js +20 -24
  562. package/lib/url/URLParserPlugin.js +26 -13
  563. package/lib/util/ArrayQueue.js +3 -3
  564. package/lib/util/AsyncQueue.js +4 -3
  565. package/lib/util/Hash.js +5 -1
  566. package/lib/util/LazySet.js +35 -22
  567. package/lib/util/LocConverter.js +36 -13
  568. package/lib/util/SourceProcessor.js +1066 -24
  569. package/lib/util/StringXor.js +1 -1
  570. package/lib/util/URLAbsoluteSpecifier.js +3 -1
  571. package/lib/util/chainedImports.js +9 -5
  572. package/lib/util/cleverMerge.js +1 -1
  573. package/lib/util/comparators.js +45 -14
  574. package/lib/util/concatenate.js +203 -77
  575. package/lib/util/conventions.js +10 -2
  576. package/lib/util/createHash.js +2 -2
  577. package/lib/util/createHooksRegistry.js +8 -10
  578. package/lib/util/createMappings.js +25 -3
  579. package/lib/util/dataURL.js +225 -1
  580. package/lib/util/extractSourceMap.js +4 -3
  581. package/lib/util/findCaseMismatch.js +139 -0
  582. package/lib/util/formatLocation.js +1 -2
  583. package/lib/util/fs.js +22 -5
  584. package/lib/util/globUtils.js +298 -24
  585. package/lib/util/hash/BatchedHash.js +5 -1
  586. package/lib/util/hash/BulkUpdateHash.js +5 -1
  587. package/lib/util/hash/DebugHash.js +5 -1
  588. package/lib/util/hash/hash-digest.js +6 -2
  589. package/lib/util/identifier.js +4 -0
  590. package/lib/util/implicitTypeLoaderFallback.js +1 -1
  591. package/lib/util/internalSerializables.js +8 -0
  592. package/lib/util/lazyModule.js +56 -0
  593. package/lib/util/makeSerializable.js +7 -3
  594. package/lib/util/matchAlias.js +25 -0
  595. package/lib/util/mimeTypes.js +11 -5
  596. package/lib/util/nonNumericOnlyHash.js +4 -3
  597. package/lib/util/parseJson.js +5 -3
  598. package/lib/util/preloadModuleType.js +32 -0
  599. package/lib/util/registerExternalSerializer.js +7 -5
  600. package/lib/util/removeBOM.js +82 -1
  601. package/lib/util/runtime.js +2 -2
  602. package/lib/util/semver.js +1 -1
  603. package/lib/util/serialization.js +28 -28
  604. package/lib/util/source.js +2 -2
  605. package/lib/util/traverseDestructuringAssignmentProperties.js +6 -2
  606. package/lib/wasm/EnableWasmLoadingPlugin.js +10 -8
  607. package/lib/wasm/wasmModuleFilename.js +54 -0
  608. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +43 -21
  609. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +45 -21
  610. package/lib/wasm-async/AsyncWasmModule.js +3 -3
  611. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +4 -5
  612. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +57 -17
  613. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +34 -18
  614. package/lib/wasm-async/AsyncWebAssemblyParser.js +9 -8
  615. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +29 -8
  616. package/lib/wasm-sync/SyncWasmModule.js +2 -2
  617. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +18 -13
  618. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -5
  619. package/lib/wasm-sync/WebAssemblyGenerator.js +18 -17
  620. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +4 -4
  621. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +7 -7
  622. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +24 -11
  623. package/lib/wasm-sync/WebAssemblyParser.js +4 -6
  624. package/lib/wasm-sync/WebAssemblyUtils.js +2 -2
  625. package/lib/web/FetchCompileAsyncWasmPlugin.js +105 -19
  626. package/lib/web/FetchCompileWasmPlugin.js +48 -16
  627. package/lib/web/JsonpChunkLoadingPlugin.js +47 -23
  628. package/lib/web/JsonpChunkLoadingRuntimeModule.js +50 -20
  629. package/lib/web/JsonpTemplatePlugin.js +2 -2
  630. package/lib/webpack.js +22 -11
  631. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +60 -26
  632. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -32
  633. package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
  634. package/module.d.ts +1 -0
  635. package/package.json +32 -25
  636. package/schemas/WebpackOptions.check.js +1 -1
  637. package/schemas/WebpackOptions.json +667 -34
  638. package/schemas/plugins/HtmlParserOptions.check.js +1 -1
  639. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  640. package/schemas/plugins/container/ContainerPlugin.json +10 -0
  641. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  642. package/schemas/plugins/container/ModuleFederationPlugin.json +10 -0
  643. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
  644. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  645. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  646. package/types.d.ts +3223 -465
  647. package/lib/runtime/CommonJsWrapRuntimeModule.js +0 -37
@@ -5,23 +5,28 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const { CachedSource, ReplaceSource } = require("webpack-sources");
9
+ const APIPlugin = require("./APIPlugin");
10
+
8
11
  const InitFragment = require("./InitFragment");
9
12
  const {
13
+ ASSET_TYPE,
14
+ ASSET_URL_TYPE,
15
+ CSS_TYPE,
16
+ HTML_TYPE,
10
17
  JAVASCRIPT_TYPE,
11
18
  RUNTIME_TYPE
12
19
  } = require("./ModuleSourceTypeConstants");
13
- const {
14
- WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE,
15
- WEBPACK_MODULE_TYPE_FALLBACK,
16
- WEBPACK_MODULE_TYPE_PROVIDE,
17
- WEBPACK_MODULE_TYPE_REMOTE
18
- } = require("./ModuleTypeConstants");
20
+ const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("./ModuleTypeConstants");
19
21
  const RuntimeGlobals = require("./RuntimeGlobals");
20
22
  const Template = require("./Template");
21
23
  const {
22
24
  getOutgoingAsyncModules
23
25
  } = require("./async-modules/AsyncModuleHelpers");
26
+ const HarmonyImportDependency = require("./dependencies/HarmonyImportDependency");
27
+ const ImportDependency = require("./dependencies/ImportDependency");
24
28
  const { ImportPhaseUtils } = require("./dependencies/ImportPhase");
29
+ const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
25
30
  const { InlinedUsedName } = require("./optimize/InlineExports");
26
31
  const {
27
32
  getDeferredCycleModuleIds,
@@ -29,56 +34,340 @@ const {
29
34
  getMakeDeferredNamespaceModeFromExportsType,
30
35
  getOptimizedDeferredModule
31
36
  } = require("./runtime/MakeDeferredNamespaceObjectRuntime");
37
+ const {
38
+ isAbsoluteBaseUri,
39
+ isChunkRelativeBaseUri
40
+ } = require("./runtime/baseUri");
32
41
  const { equals } = require("./util/ArrayHelpers");
42
+ const { getScheme } = require("./util/URLAbsoluteSpecifier");
43
+ const { compareIds } = require("./util/comparators");
33
44
  const compileBooleanMatcher = require("./util/compileBooleanMatcher");
34
45
  const { getUndoPath, toJsStringLiteral } = require("./util/identifier");
35
46
  const memoize = require("./util/memoize");
36
47
  const { propertyAccess, propertyName } = require("./util/property");
37
- const { forEachRuntime, subtractRuntime } = require("./util/runtime");
48
+ const {
49
+ forEachRuntime,
50
+ getRuntimeKey,
51
+ intersectRuntime,
52
+ subtractRuntime
53
+ } = require("./util/runtime");
38
54
 
39
- const getHarmonyImportDependency = memoize(() =>
40
- require("./dependencies/HarmonyImportDependency")
41
- );
42
- const getImportDependency = memoize(() =>
43
- require("./dependencies/ImportDependency")
44
- );
45
- const getJavascriptModulesPlugin = memoize(() =>
46
- require("./javascript/JavascriptModulesPlugin")
47
- );
48
- const getModuleHotAcceptDependency = memoize(() =>
49
- require("./dependencies/ModuleHotAcceptDependency")
50
- );
51
- const getAPIPlugin = memoize(() => require("./APIPlugin"));
55
+ const getCssModulesPlugin = memoize(() => require("./css/CssModulesPlugin"));
56
+ // `Compilation` requires this module, so its stage constants are read lazily.
57
+ const getCompilation = memoize(() => require("./Compilation"));
58
+ const getExternalModule = memoize(() => require("./ExternalModule"));
52
59
 
53
- // Module-federation module types whose chunks load through the federation runtime.
54
- /** @type {Set<string>} */
55
- const FEDERATION_MODULE_TYPES = new Set([
56
- WEBPACK_MODULE_TYPE_REMOTE,
57
- WEBPACK_MODULE_TYPE_PROVIDE,
58
- WEBPACK_MODULE_TYPE_CONSUME_SHARED_MODULE,
59
- WEBPACK_MODULE_TYPE_FALLBACK
60
+ /**
61
+ * @typedef {object} ChunkAssetNaming
62
+ * @property {(chunk: Chunk, outputOptions: OutputOptions) => ChunkFilenameTemplate} template what names the asset
63
+ * @property {SpecifierPartKind} standIn the stand-in kind that spells it once the hashes exist
64
+ */
65
+
66
+ /**
67
+ * What names the asset a chunk emits for one source type. Keyed rather than branched
68
+ * on, so a type nothing here answers for keeps the runtime form instead of silently
69
+ * taking another type's name and hash. A plugin emitting a new kind of chunk asset
70
+ * registers it here to have its urls baked.
71
+ * @type {Map<string, ChunkAssetNaming>}
72
+ */
73
+ const CHUNK_ASSET_NAMING = new Map([
74
+ [
75
+ JAVASCRIPT_TYPE,
76
+ {
77
+ template: (chunk, outputOptions) =>
78
+ JavascriptModulesPlugin.getChunkFilenameTemplate(chunk, outputOptions),
79
+ standIn: "chunk"
80
+ }
81
+ ],
82
+ [
83
+ CSS_TYPE,
84
+ {
85
+ template: (chunk, outputOptions) =>
86
+ getCssModulesPlugin().getChunkFilenameTemplate(chunk, outputOptions),
87
+ standIn: "cssChunk"
88
+ }
89
+ ]
60
90
  ]);
91
+ const getTemplatedPathPlugin = memoize(() => require("./TemplatedPathPlugin"));
92
+ const getConcatenatedModule = memoize(() =>
93
+ require("./optimize/ConcatenatedModule")
94
+ );
61
95
 
62
96
  // Any `[hash]`/`[fullhash]`/`[chunkhash]`/`[contenthash]` token, incl. a `:<length>`
63
97
  // or `:<digest>[:<length>]` suffix (e.g. `[contenthash:base64:8]`). Its value is only
64
98
  // resolved after code generation, so a filename using one can't be an inline literal.
65
99
  const HASH_IN_FILENAME = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/;
100
+ // Two stand-ins for every hash a filename function might read: a name built from one
101
+ // is hash-dependent exactly when the two calls disagree.
102
+ const HASH_PROBE = "0123456789abcdef0123";
103
+ // Reversed, so the two differ at every position and no slice of one equals the other.
104
+ const HASH_PROBE_ALTERNATE = "3210fedcba9876543210";
66
105
  const HASH_IN_FILENAME_GLOBAL = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/g;
67
106
 
68
- /** @typedef {import("./config/defaults").OutputNormalizedWithDefaults} OutputOptions */
69
- /** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
70
- /** @typedef {import("./Chunk")} Chunk */
71
- /** @typedef {import("./ChunkGraph")} ChunkGraph */
72
- /** @typedef {import("./Compilation")} Compilation */
73
- /** @typedef {import("./Dependency")} Dependency */
74
- /** @typedef {import("./Module")} Module */
75
- /** @typedef {import("./Module").BuildMeta} BuildMeta */
76
- /** @typedef {import("./Module").RuntimeRequirements} RuntimeRequirements */
77
- /** @typedef {import("./ModuleGraph")} ModuleGraph */
78
- /** @typedef {import("./RequestShortener")} RequestShortener */
79
- /** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
80
- /** @typedef {import("./dependencies/ImportPhase").ImportPhaseType} ImportPhaseType */
81
- /** @typedef {import("./NormalModuleFactory").ModuleDependency} ModuleDependency */
107
+ /**
108
+ * @param {SpecifierPart} part one piece of a reserved name
109
+ * @returns {boolean} true when it is text the deferred pass adds nothing to
110
+ */
111
+ const isLiteralPart = (part) => part[0] === "literal";
112
+
113
+ /**
114
+ * The text these parts spell, or `null` when one of them is a stand-in that only
115
+ * the deferred pass can fill in.
116
+ * @param {SpecifierPart[] | null} parts pieces of a name
117
+ * @returns {string | null} the text, or `null` when they are not all literal
118
+ */
119
+ const literalText = (parts) => {
120
+ if (parts === null) return null;
121
+ // Built in one pass rather than tested and then joined: every specifier asks, and
122
+ // a stand-in in the first part answers without reading the rest.
123
+ let text = "";
124
+ for (const part of parts) {
125
+ if (!isLiteralPart(part)) return null;
126
+ text += part[1];
127
+ }
128
+ return text;
129
+ };
130
+
131
+ /**
132
+ * Whether a public path reaches the same place from any base. A relative one does
133
+ * not, and is equivalent only behind the `../` path back to the output root.
134
+ * @param {string} publicPath the resolved public path, or the shape of one
135
+ * @returns {boolean} true when no base is needed
136
+ */
137
+ const isBaseIndependent = (publicPath) =>
138
+ publicPath.startsWith("/") || getScheme(publicPath) !== undefined;
139
+
140
+ /**
141
+ * Drops the `./` a public path may open with: what follows it is already walked back
142
+ * to the output root, so it would only lengthen the name.
143
+ * @param {SpecifierPart[]} parts a public path's pieces
144
+ * @returns {SpecifierPart[]} them, without that `./`
145
+ */
146
+ const rootedParts = (parts) =>
147
+ parts.length > 0 &&
148
+ isLiteralPart(parts[0]) &&
149
+ /** @type {string} */ (parts[0][1]).startsWith("./")
150
+ ? [
151
+ /** @type {SpecifierPart} */ ([
152
+ "literal",
153
+ /** @type {string} */ (parts[0][1]).slice(2)
154
+ ]),
155
+ ...parts.slice(1)
156
+ ]
157
+ : parts;
158
+
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
+ /**
175
+ * Where a literal is read from — the `../` path back to the output root, and whether
176
+ * the chunk loader fetched the chunk it sits in through `output.publicPath`.
177
+ * @typedef {object} Placement
178
+ * @property {string | null} undo the path back to the output root
179
+ * @property {boolean | null} loaded whether the chunk loader fetched the chunk
180
+ */
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
+ /**
190
+ * @typedef {object} WasmGroups
191
+ * @property {(key: string) => string} groupOf the group a runtime key answers with
192
+ * @property {Set<string>} fetching groups an entry of which reads binaries with `fetch`
193
+ * @property {Map<string, boolean>} onlyFetching groups every entry of which fetches
194
+ */
195
+
196
+ // A reference in no chunk at all: nothing is known about where it is read from.
197
+ /** @type {Placement} */
198
+ const NO_PLACEMENT = { undo: null, loaded: null };
199
+
200
+ /**
201
+ * Which of `createHash`'s four rounds settles this chunk's hash. A hash may only be
202
+ * read from an earlier round, which is what lets one chunk's name be folded into
203
+ * another's hash.
204
+ * @param {Chunk} chunk the chunk
205
+ * @param {ChunkGraph} chunkGraph the chunk graph
206
+ * @returns {number} the round, ascending
207
+ */
208
+ const hashRound = (chunk, chunkGraph) => {
209
+ if (chunk.hasRuntime()) return 2;
210
+ if (chunkGraph.getNumberOfEntryModules(chunk) > 0) return 3;
211
+ return chunk.canBeInitial() ? 1 : 0;
212
+ };
213
+
214
+ // The round runtime chunks are settled in, ordered by references between them rather
215
+ // than by id, so id says nothing about the order inside it.
216
+ const RUNTIME_HASH_ROUND = 2;
217
+
218
+ // Why a public path needing a base could not be spelled from the chunk holding it.
219
+ 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";
221
+
222
+ /**
223
+ * @import {
224
+ * OutputNormalizedWithDefaults as OutputOptions
225
+ * } from "./config/defaults"
226
+ */
227
+ /** @import { PublicPath, WasmLoading } from "../declarations/WebpackOptions" */
228
+ /** @import ModuleDependency from "./dependencies/ModuleDependency" */
229
+ /**
230
+ * @import Module, {
231
+ * ReadOnlyRuntimeRequirements,
232
+ * BuildMeta,
233
+ * RuntimeRequirements
234
+ * } from "./Module"
235
+ */
236
+ /** @typedef {"import" | "url" | "url-runtime" | "url-inline" | "wasm" | "wasm-relative"} AnalyzableForm */
237
+ /**
238
+ * One piece of a name only the deferred pass can spell: text as it stands, the `../`
239
+ * path from the asset it sits in to the output root, a template or `output.publicPath`
240
+ * 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
243
+ */
244
+ /** @typedef {[SpecifierPartKind, string | number]} SpecifierPart */
245
+
246
+ const SPECIFIER_PART_KINDS = new Set([
247
+ "literal",
248
+ "undo",
249
+ "template",
250
+ "publicPath",
251
+ "unserved",
252
+ "base",
253
+ "chunk",
254
+ "cssChunk"
255
+ ]);
256
+
257
+ // Only these carry a chunk id, which is the one part value that may be a number.
258
+ const CHUNK_SPECIFIER_PART_KINDS = new Set(["chunk", "cssChunk"]);
259
+
260
+ // Only these are spelled out of the compilation hash, so a stand-in holding one moves
261
+ // the chunk it lands in into the round after that hash settles.
262
+ const FULL_HASH_PART_KINDS = new Set(["publicPath", "template", "unserved"]);
263
+
264
+ // What the deferred pass scans for — the other half of what the class spells.
265
+ const ANALYZABLE_TOKEN_REGEXP = /\.\/@@webpackAnalyzableChunk:([\w-]+)@@/g;
266
+
267
+ // Stands in for the compilation hash inside an otherwise resolved filename, with the
268
+ // requested length when the placeholder asked for one.
269
+ const FULL_HASH_TOKEN_REGEXP = /@@webpackFullHash(?:-(\d+))?@@/g;
270
+
271
+ const FULL_HASH_TOKEN_PREFIX = "@@webpackFullHash";
272
+
273
+ /**
274
+ * @param {number=} length how many characters the placeholder asked for
275
+ * @returns {string} the stand-in to emit
276
+ */
277
+ const reserveFullHash = (length) =>
278
+ `${FULL_HASH_TOKEN_PREFIX}${length === undefined ? "" : `-${length}`}@@`;
279
+
280
+ // `getPath` data that leaves every compilation-hash placeholder as a stand-in while the
281
+ // rest of the name resolves — a module's own hash and id are settled during code
282
+ // generation, the compilation's is not. Shared: it closes over nothing.
283
+ const DEFERRED_FULL_HASH_PATH_DATA = {
284
+ hash: reserveFullHash(),
285
+ hashWithLength: reserveFullHash
286
+ };
287
+
288
+ // The same table read by stand-in, for the pass that spells one: a chunk's content hash
289
+ // is keyed by source type, so the type it is keyed under here is the hash to read.
290
+ const CHUNK_ASSET_NAMING_BY_STAND_IN = new Map(
291
+ [...CHUNK_ASSET_NAMING].map(([contentHashType, naming]) => [
292
+ naming.standIn,
293
+ { template: naming.template, contentHashType }
294
+ ])
295
+ );
296
+
297
+ /**
298
+ * first character, last character, replacement.
299
+ * @typedef {[number, number, string]} Replacement
300
+ */
301
+
302
+ const PASS_NAME = "analyzableChunkNaming";
303
+
304
+ /** @import AsyncDependenciesBlock from "./AsyncDependenciesBlock" */
305
+ /** @import { Source } from "webpack-sources" */
306
+ /** @import Compiler from "./Compiler" */
307
+ /** @import Chunk, { ChunkFilenameTemplate, ChunkId } from "./Chunk" */
308
+ /** @import ChunkGroup from "./ChunkGroup" */
309
+ /** @import ChunkGraph from "./ChunkGraph" */
310
+ /** @import Compilation from "./Compilation" */
311
+ /** @import Dependency from "./Dependency" */
312
+ /** @import ModuleGraph from "./ModuleGraph" */
313
+ /** @import RequestShortener from "./RequestShortener" */
314
+ /** @import Hash from "./util/Hash" */
315
+ /** @import CodeGenerationResults from "./CodeGenerationResults" */
316
+ /** @import { RuntimeSpec } from "./util/runtime" */
317
+
318
+ /**
319
+ * A stand-in whose every hash reads back as `hash`. Which content hashes a chunk
320
+ * carries is settled after code generation, so `present` makes the two probes disagree
321
+ * about that too — a name built by enumerating them then reads as hash-dependent.
322
+ * Shadows the chunk rather than mutating it, so a filename function still reads every
323
+ * other field and method straight off it.
324
+ * @param {Chunk} chunk the chunk being referenced
325
+ * @param {string} hash the stand-in hash
326
+ * @param {boolean} present whether the chunk is claimed to carry content hashes
327
+ * @returns {Chunk} the stand-in chunk
328
+ */
329
+ const createHashProbeChunk = (chunk, hash, present) => {
330
+ const probeChunk = Object.create(chunk);
331
+ probeChunk.hash = hash;
332
+ probeChunk.renderedHash = hash;
333
+ probeChunk.contentHash = new Proxy(
334
+ present ? { [JAVASCRIPT_TYPE]: hash } : {},
335
+ {
336
+ // Any content-hash type, not only the ones this chunk happens to carry.
337
+ get: (target, key) => (typeof key === "string" ? hash : undefined),
338
+ has: () => present,
339
+ getOwnPropertyDescriptor: () =>
340
+ present
341
+ ? {
342
+ value: hash,
343
+ writable: true,
344
+ enumerable: true,
345
+ configurable: true
346
+ }
347
+ : undefined
348
+ }
349
+ );
350
+ return probeChunk;
351
+ };
352
+
353
+ /**
354
+ * A filename function's answer to the stand-in hash, which says what shape the name
355
+ * has before any real hash exists.
356
+ * @param {Exclude<ChunkFilenameTemplate, string>} template the filename function
357
+ * @param {Chunk} chunk the chunk being referenced
358
+ * @param {string} contentHashType which of the chunk's hashes the name reads
359
+ * @param {string} hash the stand-in hash
360
+ * @param {boolean} present whether the chunk is claimed to carry content hashes
361
+ * @returns {string} what the function names it
362
+ */
363
+ const probeTemplateName = (template, chunk, contentHashType, hash, present) =>
364
+ template({
365
+ chunk: createHashProbeChunk(chunk, hash, present),
366
+ runtime: chunk.runtime,
367
+ contentHashType,
368
+ hash,
369
+ contentHash: hash
370
+ });
82
371
 
83
372
  /**
84
373
  * No module id error message.
@@ -107,6 +396,10 @@ Module has these incoming connections: ${Array.from(
107
396
  }`
108
397
  ).join("")}`;
109
398
 
399
+ // `this` as a value, not as a property name or part of a longer identifier
400
+ // (identifier characters per `getGlobalObject` below, so `globalThis` is not one)
401
+ const THIS_REFERENCE_REGEXP = /(?:^|[^\p{L}\p{N}_$.])this(?![\p{L}\p{N}_$])/u;
402
+
110
403
  /**
111
404
  * Gets global object.
112
405
  * @param {string | undefined} definition global object definition
@@ -130,6 +423,11 @@ function getGlobalObject(definition) {
130
423
  return `Object(${trimmed})`;
131
424
  }
132
425
 
426
+ // An async external is a promise, not a module record with an evaluating state.
427
+ const isAsyncExternal = (/** @type {Module} */ module) =>
428
+ Boolean(/** @type {BuildMeta} */ (module.buildMeta).async) &&
429
+ module instanceof getExternalModule();
430
+
133
431
  class RuntimeTemplate {
134
432
  /**
135
433
  * Creates an instance of RuntimeTemplate.
@@ -149,12 +447,47 @@ class RuntimeTemplate {
149
447
  (getGlobalObject(outputOptions.globalObject));
150
448
  /** @type {string} */
151
449
  this.contentHashReplacement = "X".repeat(outputOptions.hashDigestLength);
450
+ /** @type {boolean | undefined} */
451
+ this._javascriptNamedWithoutContent = undefined;
452
+ /** @type {WeakMap<Chunk, boolean>} */
453
+ this._chunkNamedWithoutContent = new WeakMap();
454
+ /** @type {WeakMap<Chunk, string>} */
455
+ this._foldedAnalyzableNames = new WeakMap();
456
+ /** @type {WeakMap<Chunk, Map<string, string>>} */
457
+ this._analyzableAssetNames = new WeakMap();
458
+ /** @type {Map<Chunk, Set<string>> | undefined} */
459
+ this._namesBakedInto = undefined;
460
+ /** @type {Map<string, Chunk> | undefined} */
461
+ this._chunksByIdForFold = undefined;
462
+ /** @type {Set<Chunk> | undefined} */
463
+ this._chunksBakingFullHash = undefined;
464
+ /** @type {string | false | undefined} */
465
+ this._publicPathShapeText = undefined;
466
+ /** @type {string | null | undefined} */
467
+ this._publicPathClimbText = undefined;
468
+ /** @type {WeakMap<Chunk, Placement>} */
469
+ this._placementByChunk = new WeakMap();
470
+ /** @type {Map<string, string | null | undefined>} */
471
+ this._entryBaseUriByRuntime = new Map();
472
+ /** @type {WasmGroups | undefined} */
473
+ this._wasmGroupsValue = undefined;
474
+ /** @type {Map<string, boolean> | undefined} */
475
+ this._wasmAnchorKnownByGroup = undefined;
152
476
  }
153
477
 
154
478
  isIIFE() {
155
479
  return this.outputOptions.iife;
156
480
  }
157
481
 
482
+ /**
483
+ * Whether the global object expression reads the `this` binding, which only
484
+ * refers to the global object outside of strict mode.
485
+ * @returns {boolean} true, when it reads `this`
486
+ */
487
+ globalObjectUsesThis() {
488
+ return THIS_REFERENCE_REGEXP.test(this.globalObject);
489
+ }
490
+
158
491
  isModule() {
159
492
  return this.outputOptions.module;
160
493
  }
@@ -191,8 +524,10 @@ class RuntimeTemplate {
191
524
 
192
525
  /**
193
526
  * Expression for the global registry that collects CSS server-side when there
194
- * is no DOM (SSR). An SSR host reads it from `globalThis`; it is keyed by the
195
- * style/chunk identifier and namespaced by `output.uniqueName`.
527
+ * is no DOM (SSR). Read it with `__webpack_css_server_styles__`; it is keyed
528
+ * by the style/chunk identifier and namespaced by `output.uniqueName`.
529
+ * Targets without `globalThis` go through the `__webpack_require__.g`
530
+ * polyfill, so consumers must also require `RuntimeGlobals.global`.
196
531
  * @returns {string} runtime expression evaluating to the registry object
197
532
  */
198
533
  cssServerStyleRegistry() {
@@ -200,7 +535,10 @@ class RuntimeTemplate {
200
535
  const key = JSON.stringify(
201
536
  name ? `__webpack_css__${name}` : "__webpack_css__"
202
537
  );
203
- return `(${this.assignOr(`globalThis[${key}]`, "{}")})`;
538
+ const global = this.outputOptions.environment.globalThis
539
+ ? "globalThis"
540
+ : RuntimeGlobals.global;
541
+ return `(${this.assignOr(`${global}[${key}]`, "{}")})`;
204
542
  }
205
543
 
206
544
  supportsConst() {
@@ -267,168 +605,855 @@ class RuntimeTemplate {
267
605
  return this.outputOptions.environment.module;
268
606
  }
269
607
 
608
+ supportsDeferImport() {
609
+ return this.outputOptions.environment.deferImport;
610
+ }
611
+
612
+ supportsSourceImport() {
613
+ return this.outputOptions.environment.sourceImport;
614
+ }
615
+
270
616
  supportsModulePreload() {
271
617
  return this.outputOptions.environment.modulePreload;
272
618
  }
273
619
 
274
- supportsAnalyzableEsm() {
620
+ /**
621
+ * Whether a reference a foreign bundler can follow without running webpack's runtime
622
+ * may be emitted — the one question every caller asks, in the form it is asking for:
623
+ *
624
+ * - `"import"` — a literal `import("./chunk.js")` in place of `ensureChunk(id)`
625
+ * - `"url"` — a literal `new URL(<file>, import.meta.url)`
626
+ * - `"url-runtime"` — the same, written into a runtime module rather than a module
627
+ * - `"url-inline"` — whether such a reference names the file at the call site
628
+ * - `"wasm"` — the same, fully baked for a wasm binary the runtime would name
629
+ * - `"wasm-relative"` — a wasm path built at runtime under an `import.meta.url` base
630
+ *
631
+ * `"url-inline"` differs from `"url"` only in taking the `.p + <file>` fallback as
632
+ * an answer too — both name the file where it is used rather than through the
633
+ * asset's javascript wrapper, which is what decides whether that wrapper is emitted.
634
+ *
635
+ * A name code generation cannot settle may still be baked, through a stand-in the
636
+ * deferred pass fills in. Not covered here, because only the reference can tell: a
637
+ * chunk with no id, and one this compilation emits no javascript for.
638
+ * @param {AnalyzableForm} form which reference is being emitted
639
+ * @param {ChunkGraph=} chunkGraph the chunk graph, to place `module` in its runtimes
640
+ * @param {Module=} module the module the reference is emitted into
641
+ * @param {RuntimeSpec=} runtime the runtime the reference is emitted for; the wasm forms answer for the loader it shares rather than for every loader in the compilation
642
+ * @returns {boolean} true when the literal form may be emitted
643
+ */
644
+ supportsAnalyzable(form, chunkGraph, module, runtime) {
645
+ // Analyzable output is ESM output — anything else is a different feature.
646
+ if (!this.isModule()) return false;
647
+ // Build-time execution keeps the runtime form — `import.meta` does not parse in its
648
+ // vm wrapper. Unreported on purpose: its chunk graph shares the real module graph.
649
+ if (chunkGraph && chunkGraph.buildTimeExecution) return false;
650
+ const { outputOptions } = this;
651
+ // One loader per runtime serves every wasm module in it, so the answer has to
652
+ // hold compilation-wide — else a baked url reaches the id-and-hash signature.
653
+ const scoped = form !== "wasm" && form !== "wasm-relative";
654
+ // Resolved once: concatenation may have absorbed the module that wrote the
655
+ // reference, and both the scope below and the worker loop ask about the same one.
656
+ const placedModule =
657
+ scoped && module !== undefined
658
+ ? getConcatenatedModule().getChunkGraphModule(this.compilation, module)
659
+ : undefined;
660
+ // A reassigned `__webpack_public_path__` cannot reach a baked literal, and `.p`
661
+ // 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.
664
+ if (
665
+ form !== "url-inline" &&
666
+ APIPlugin.runtimeUsesPublicPathOverride(
667
+ this.compilation,
668
+ scoped ? chunkGraph : undefined,
669
+ placedModule
670
+ )
671
+ ) {
672
+ return this._analyzableBailout(
673
+ module,
674
+ "__webpack_public_path__ is reassigned in a runtime this module belongs to",
675
+ false
676
+ );
677
+ }
678
+
679
+ if (form === "import") {
680
+ // 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
+ }
710
+ }
711
+ return true;
712
+ }
713
+
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.
717
+ // `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.
720
+ if (form === "url-inline") return true;
275
721
  // `eval` devtool wraps each module in `eval(...)`, where `import.meta` is a
276
- // syntax error, so the literal `new URL(…, import.meta.url)` form can't be used.
722
+ // syntax error. Runtime modules are emitted beside them, never wrapped.
277
723
  const { devtool } = this.compilation.options;
278
- return (
279
- this.isModule() &&
280
- this.supportsEcmaScriptModuleSyntax() &&
281
- !(typeof devtool === "string" && devtool.includes("eval")) &&
282
- // A runtime `__webpack_public_path__` override can't be reflected in a
283
- // baked literal, so keep the runtime form that reads `__webpack_require__.p`.
284
- !getAPIPlugin().usesRuntimePublicPathOverride(this.compilation)
285
- );
286
- }
287
-
288
- supportTemplateLiteral() {
289
- return this.outputOptions.environment.templateLiteral;
290
- }
724
+ if (
725
+ form !== "url-runtime" &&
726
+ typeof devtool === "string" &&
727
+ devtool.includes("eval")
728
+ ) {
729
+ return this._analyzableBailout(
730
+ module,
731
+ `devtool ${JSON.stringify(devtool)} wraps the module in eval(), where import.meta does not parse`,
732
+ false
733
+ );
734
+ }
735
+ if (form === "url" || form === "url-runtime") return true;
736
+ // A bare relative URL is what `__webpack_require__.p + path` means only under an
737
+ // `auto` public path; anything else has to be baked, which is the "wasm" form.
738
+ if (form === "wasm-relative") {
739
+ if (outputOptions.publicPath === "auto") return true;
740
+ return this._analyzableBailout(
741
+ module,
742
+ "output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to",
743
+ false
744
+ );
745
+ }
291
746
 
292
- supportNodePrefixForCoreModules() {
293
- return this.outputOptions.environment.nodePrefixForCoreModules;
747
+ // The rest is the `"wasm"` form: whether the whole binary url can be spelled
748
+ // here, rather than built at runtime under an `import.meta.url` base.
749
+ const { publicPath, webassemblyModuleFilename } = outputOptions;
750
+ if (publicPath !== "auto") {
751
+ // A public path that needs no base names the same place from the chunk as from
752
+ // the document, so a literal spells what `fetch` would have reached.
753
+ if (this._publicPathNeedsNoBase()) {
754
+ // Settled no earlier than the hash it reads or is called with, so it is
755
+ // baked only where the deferred pass may finish it.
756
+ if (this._resolvePublicPathPrefix(publicPath, module) === null) {
757
+ return false;
758
+ }
759
+ } else if (
760
+ this._anyWasmChunkFetches(runtime) &&
761
+ !this._wasmFetchAnchorIsKnown(runtime)
762
+ ) {
763
+ return this._analyzableBailout(
764
+ module,
765
+ "output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from",
766
+ false
767
+ );
768
+ }
769
+ }
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
+ return true;
294
782
  }
295
783
 
296
784
  /**
297
- * Renders node prefix for core module.
298
- * @param {string} mod a module
299
- * @returns {string} a module with `node:` prefix when supported, otherwise an original name
785
+ * Records why a reference kept the runtime form, on the module that wrote it —
786
+ * the channel `ModuleConcatenationPlugin` already reports through, so it reaches
787
+ * `stats.optimizationBailout`. Silent unless the build asked for ESM output, where
788
+ * alone the answer is actionable; deduplicated because a module may write many.
789
+ * Answers with `answer` so a caller states the refusal and its reason at once —
790
+ * `false` where it answers a question, `null` where it was building a specifier.
791
+ * @template {false | null} T
792
+ * @param {Module | undefined} module the module the reference is emitted into
793
+ * @param {string} reason why no literal could be baked
794
+ * @param {T} answer what the caller hands back
795
+ * @returns {T} that answer
300
796
  */
301
- renderNodePrefixForCoreModule(mod) {
302
- return this.outputOptions.environment.nodePrefixForCoreModules
303
- ? `"node:${mod}"`
304
- : `"${mod}"`;
797
+ _analyzableBailout(module, reason, answer) {
798
+ if (module !== undefined && this.outputOptions.module) {
799
+ const text = `Analyzable ESM bailout: ${reason}`;
800
+ const bailouts =
801
+ this.compilation.moduleGraph.getOptimizationBailout(module);
802
+ if (!bailouts.includes(text)) bailouts.push(text);
803
+ }
804
+ return answer;
305
805
  }
306
806
 
307
807
  /**
308
- * Renders return const when it is supported, otherwise let when supported, otherwise var.
309
- * @returns {"const" | "let" | "var"} return `const` when it is supported, otherwise `let` when supported, otherwise `var`
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
310
820
  */
311
- renderConst() {
312
- return this.supportsConst() ? "const" : this.supportsLet() ? "let" : "var";
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
+ );
828
+ }
829
+ return this._javascriptNamedWithoutContent;
830
+ }
831
+ let found = false;
832
+ for (const chunk of chunks) {
833
+ found = true;
834
+ if (!this._chunkNameIndependentOfContent(chunk)) return false;
835
+ }
836
+ // None at all names nothing to reason about — the asset is unknown, not safe.
837
+ return found;
313
838
  }
314
839
 
315
840
  /**
316
- * Renders return let when it is supported, otherwise var.
317
- * @returns {"let" | "var"} return `let` when it is supported, otherwise `var`
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
318
846
  */
319
- renderLet() {
320
- return this.supportsLet() ? "let" : "var";
847
+ _canDeferOrBail(chunks, module) {
848
+ if (this._canDeferAnalyzableName(chunks)) return true;
849
+ return this._analyzableBailout(module, DEFER_BAILOUT, false);
321
850
  }
322
851
 
323
852
  /**
324
- * Returning function.
325
- * @param {string} returnValue return value
326
- * @param {string} args arguments
327
- * @returns {string} returning function
853
+ * These parts as a quoted specifier: the text itself where they spell one already,
854
+ * and a stand-in for the deferred pass where they do not.
855
+ * @param {SpecifierPart[]} parts the whole specifier
856
+ * @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
328
860
  */
329
- returningFunction(returnValue, args = "") {
330
- return this.supportsArrowFunction()
331
- ? `(${args}) => (${returnValue})`
332
- : `function(${args}) { return ${returnValue}; }`;
861
+ _specifierOf(parts, chunks, module) {
862
+ const text = literalText(parts);
863
+ 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));
333
874
  }
334
875
 
335
876
  /**
336
- * Returns basic function.
337
- * @param {string} args arguments
338
- * @param {string | string[]} body body
339
- * @returns {string} basic function
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
340
885
  */
341
- basicFunction(args, body) {
342
- return this.supportsArrowFunction()
343
- ? `(${args}) => {\n${Template.indent(body)}\n}`
344
- : `function(${args}) {\n${Template.indent(body)}\n}`;
886
+ _canDeferOrBakeFullHash(carriesFullHash, chunks, module) {
887
+ return carriesFullHash || this._canDeferOrBail(chunks, module);
345
888
  }
346
889
 
347
890
  /**
348
- * Returns result expression.
349
- * @param {(string | { expr: string })[]} args args
350
- * @returns {string} result expression
891
+ * Whether the fill will build these parts out of the compilation hash — the same
892
+ * question `_markChunksBakingFullHash` asks of what was generated, so a stand-in this
893
+ * says yes to is one that moves its chunk into the round after that hash.
894
+ * @param {SpecifierPart[]} parts what the stand-in resolves to
895
+ * @returns {boolean} true when that hash reaches the text
351
896
  */
352
- concatenation(...args) {
353
- const len = args.length;
354
-
355
- if (len === 2) return this._es5Concatenation(args);
356
- if (len === 0) return '""';
357
- if (len === 1) {
358
- return typeof args[0] === "string"
359
- ? JSON.stringify(args[0])
360
- : `"" + ${args[0].expr}`;
361
- }
362
- if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
363
-
364
- // cost comparison between template literal and concatenation:
365
- // both need equal surroundings: `xxx` vs "xxx"
366
- // template literal has constant cost of 3 chars for each expression
367
- // es5 concatenation has cost of 3 + n chars for n expressions in row
368
- // when a es5 concatenation ends with an expression it reduces cost by 3
369
- // when a es5 concatenation starts with an single expression it reduces cost by 3
370
- // e. g. `${a}${b}${c}` (3*3 = 9) is longer than ""+a+b+c ((3+3)-3 = 3)
371
- // 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)
372
-
373
- let templateCost = 0;
374
- let concatenationCost = 0;
375
-
376
- let lastWasExpr = false;
377
- for (const arg of args) {
378
- const isExpr = typeof arg !== "string";
379
- if (isExpr) {
380
- templateCost += 3;
381
- concatenationCost += lastWasExpr ? 1 : 4;
897
+ _partsBakeFullHash(parts) {
898
+ for (const [kind, value] of parts) {
899
+ if (FULL_HASH_PART_KINDS.has(kind)) return true;
900
+ if (kind === "literal" && this._hasReservedFullHash(String(value))) {
901
+ return true;
382
902
  }
383
- lastWasExpr = isExpr;
384
- }
385
- if (lastWasExpr) concatenationCost -= 3;
386
- if (typeof args[0] !== "string" && typeof args[1] === "string") {
387
- concatenationCost -= 3;
388
903
  }
389
-
390
- if (concatenationCost <= templateCost) return this._es5Concatenation(args);
391
-
392
- return `\`${args
393
- .map((arg) => (typeof arg === "string" ? arg : `\${${arg.expr}}`))
394
- .join("")}\``;
904
+ return false;
395
905
  }
396
906
 
397
907
  /**
398
- * Returns result expression.
399
- * @param {(string | { expr: string })[]} args args (len >= 2)
400
- * @returns {string} result expression
401
- * @private
908
+ * Whether the name this chunk is emitted under is settled before its own content
909
+ * is, which is what leaves it right after a later rewrite. A filename function is
910
+ * asked rather than assumed to read a hash — the same two probes the chunk
911
+ * specifier is resolved with. Memoized per chunk: answering calls that function
912
+ * twice, and a reference asks once for every chunk it is written into.
913
+ * @param {Chunk} chunk a chunk the stand-in is written into
914
+ * @returns {boolean} true when the name does not move with the content
402
915
  */
403
- _es5Concatenation(args) {
404
- const str = args
405
- .map((arg) => (typeof arg === "string" ? JSON.stringify(arg) : arg.expr))
406
- .join(" + ");
407
-
408
- // when the first two args are expression, we need to prepend "" + to force string
409
- // concatenation instead of number addition.
410
- return typeof args[0] !== "string" && typeof args[1] !== "string"
411
- ? `"" + ${str}`
412
- : str;
916
+ _chunkNameIndependentOfContent(chunk) {
917
+ const cached = this._chunkNamedWithoutContent.get(chunk);
918
+ if (cached !== undefined) return cached;
919
+ const template = this._resolveChunkFilenameTemplate(
920
+ JavascriptModulesPlugin.getChunkFilenameTemplate(
921
+ chunk,
922
+ this.outputOptions
923
+ ),
924
+ chunk,
925
+ JAVASCRIPT_TYPE
926
+ );
927
+ let independent = false;
928
+ if (typeof template === "string") {
929
+ const kinds = getTemplatedPathPlugin().getPresentKinds(template);
930
+ // `[chunkhash]` is taken from this chunk's own modules and nothing repairs it
931
+ // afterwards, so such a name stays put while the reference it holds moves.
932
+ independent =
933
+ !kinds.has("chunkhash") &&
934
+ (!kinds.has("contenthash") ||
935
+ Boolean(this.compilation.options.optimization.realContentHash));
936
+ }
937
+ this._chunkNamedWithoutContent.set(chunk, independent);
938
+ return independent;
413
939
  }
414
940
 
415
941
  /**
416
- * Expression function.
417
- * @param {string} expression expression
418
- * @param {string} args arguments
419
- * @returns {string} expression function code
942
+ * Builds the analyzable `new URL(specifier, import.meta.url)` expression the ESM
943
+ * wasm/asset loader backends use to reference an emitted binary relative to the
944
+ * current module (via `output.importMetaName`) instead of the runtime public-path
945
+ * global — the form other bundlers and webpack itself can statically follow.
946
+ * @param {string} specifier already-rendered URL argument (a literal or expression)
947
+ * @returns {string} the `new URL(...)` expression
420
948
  */
421
- expressionFunction(expression, args = "") {
422
- return this.supportsArrowFunction()
423
- ? `(${args}) => (${expression})`
424
- : `function(${args}) { ${expression}; }`;
949
+ importMetaUrl(specifier) {
950
+ return `new URL(${specifier}, ${this.outputOptions.importMetaName}.url)`;
425
951
  }
426
952
 
427
953
  /**
428
- * Returns empty function code.
429
- * @returns {string} empty function code
954
+ * Whether a baked asset url resolves against the entry `baseUri` at all. A public
955
+ * path that reaches the same place from any base never reads `.b` — and `auto`
956
+ * resolves to an absolute url too — while output with no baked form has nothing to
957
+ * resolve. Where this is false, what `baseUri` is set to cannot reach the generated
958
+ * code, so it must not reach the module hash either: `URLDependency.updateHash`
959
+ * asks this before contributing one.
960
+ * @returns {boolean} true when the base can change what is generated
961
+ */
962
+ analyzableUrlReadsBaseUri() {
963
+ if (!this.isModule()) return false;
964
+ const { publicPath } = this.outputOptions;
965
+ if (publicPath === "auto") return false;
966
+ return !this._publicPathNeedsNoBase();
967
+ }
968
+
969
+ /**
970
+ * Whether `output.publicPath` reaches the same place from any base, so a literal may
971
+ * carry it without walking back to the output root first. One whose shape nothing
972
+ * answers needs a base as far as anything here can tell. Never asked of `auto`,
973
+ * which is no path of its own.
974
+ * @returns {boolean} true when no base is needed
975
+ */
976
+ _publicPathNeedsNoBase() {
977
+ const shape = this._publicPathShape();
978
+ return shape !== undefined && isBaseIndependent(shape);
979
+ }
980
+
981
+ /**
982
+ * Static literal specifier (already quoted) for the `new URL(<here>, import.meta.url)`
983
+ * an asset reference bakes to, or `null` to keep the runtime form. Unlike a wasm
984
+ * binary, the runtime resolves an asset url against `__webpack_require__.b` — the
985
+ * output root, or an entry `baseUri` where one is set — so that base is settled here
986
+ * before the rest of the name is.
987
+ * @param {Module} module the module the reference is emitted into
988
+ * @param {ChunkGraph} chunkGraph the chunk graph
989
+ * @param {string} filename the asset's name, relative to the output root
990
+ * @param {RuntimeSpec} runtime the runtime the code is generated for
991
+ * @returns {string | null} a quoted literal, or `null` to fall back
992
+ */
993
+ getAnalyzableAssetUrl(module, chunkGraph, filename, runtime) {
994
+ const { publicPath } = this.outputOptions;
995
+ const base = this.analyzableUrlReadsBaseUri()
996
+ ? this.entryBaseUri(runtime)
997
+ : undefined;
998
+ // No base of its own: the name is spelled against the output root, as a chunk is.
999
+ if (base === undefined) {
1000
+ return this._getAnalyzableFileSpecifier(
1001
+ module,
1002
+ chunkGraph,
1003
+ [["literal", filename]],
1004
+ true
1005
+ );
1006
+ }
1007
+ if (base === null) {
1008
+ return this._analyzableBailout(
1009
+ module,
1010
+ "the entries this module is generated for set different baseUri values, so no one url resolves for all of them",
1011
+ null
1012
+ );
1013
+ }
1014
+ // A relative one is no base of its own: the runtime reads it against the
1015
+ // chunk, so the literal spells it there rather than resolving against it.
1016
+ if (isChunkRelativeBaseUri(base)) {
1017
+ return this._getAnalyzableFileSpecifier(
1018
+ module,
1019
+ chunkGraph,
1020
+ [["literal", filename]],
1021
+ true,
1022
+ base
1023
+ );
1024
+ }
1025
+ const chunks = this._moduleChunks(module, chunkGraph);
1026
+ const parts = this._resolvePublicPathPrefix(publicPath, module, chunks);
1027
+ 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.
1032
+ if (base.startsWith("//")) {
1033
+ return this._specifierOf(
1034
+ [["literal", base], ...rootedParts(parts), ["literal", filename]],
1035
+ chunks,
1036
+ module
1037
+ );
1038
+ }
1039
+ if (!isAbsoluteBaseUri(base)) {
1040
+ return this._analyzableBailout(
1041
+ module,
1042
+ `an entry sets a baseUri of ${JSON.stringify(base)}, whose scheme names no base anything can be resolved against`,
1043
+ null
1044
+ );
1045
+ }
1046
+ // Resolved here rather than against the output root, and only an absolute base
1047
+ // settles it — a relative one has no base of its own to be read against.
1048
+ const spelled = literalText(parts);
1049
+ // A hash the deferred pass still has to fill in cannot be resolved against the
1050
+ // base here: the fill would land inside an already-resolved url, where a hash
1051
+ // opening with a letter reads as a scheme and drops the base entirely.
1052
+ const text =
1053
+ spelled !== null && !this._hasReservedFullHash(spelled) ? spelled : null;
1054
+ /** @type {URL} */
1055
+ let resolved;
1056
+ try {
1057
+ // Empty where only the deferred pass can spell the rest, which still settles
1058
+ // whether the base itself is one anything may be resolved against.
1059
+ resolved = new URL(text === null ? "" : text + filename, base);
1060
+ } catch (_error) {
1061
+ return this._analyzableBailout(
1062
+ module,
1063
+ `an entry sets a baseUri of ${JSON.stringify(base)}, which is not absolute, so no url can be resolved against it here`,
1064
+ null
1065
+ );
1066
+ }
1067
+ if (text !== null) return toJsStringLiteral(resolved.href);
1068
+ if (!this._canDeferOrBail(chunks, module)) return null;
1069
+ return toJsStringLiteral(
1070
+ this._reserveAnalyzableSpecifier([
1071
+ ["base", base],
1072
+ ...parts,
1073
+ ["literal", filename]
1074
+ ])
1075
+ );
1076
+ }
1077
+
1078
+ /**
1079
+ * The `baseUri` the entries this code runs under agree on, which replaces the output
1080
+ * root an asset url resolves against. Asked per runtime, because that is what the
1081
+ * module is generated for: two entries with different bases each get their own
1082
+ * source. `undefined` when none of them sets one, `null` when they disagree — an
1083
+ * entry that omits it disagrees with one that sets it.
1084
+ * @param {RuntimeSpec} runtime the runtime the code is generated for
1085
+ * @returns {string | null | undefined} the base those entries agree on
1086
+ */
1087
+ entryBaseUri(runtime) {
1088
+ const key = getRuntimeKey(runtime);
1089
+ if (this._entryBaseUriByRuntime.has(key)) {
1090
+ return this._entryBaseUriByRuntime.get(key);
1091
+ }
1092
+ /** @type {string | null | undefined} */
1093
+ let base;
1094
+ let found = false;
1095
+ 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.
1100
+ if (!chunk.hasRuntime()) continue;
1101
+ const entryOptions = chunk.getEntryOptions();
1102
+ // An entry this code cannot run under has no say in the base it resolves to.
1103
+ if (
1104
+ !entryOptions ||
1105
+ intersectRuntime(chunk.runtime, runtime) === undefined
1106
+ ) {
1107
+ continue;
1108
+ }
1109
+ if (found && base !== entryOptions.baseUri) {
1110
+ base = null;
1111
+ break;
1112
+ }
1113
+ base = entryOptions.baseUri;
1114
+ found = true;
1115
+ }
1116
+ this._entryBaseUriByRuntime.set(key, base);
1117
+ return base;
1118
+ }
1119
+
1120
+ /**
1121
+ * `output.publicPath` as the constant it will be, for code that would otherwise read
1122
+ * `__webpack_require__.p` for a value that never changes. `undefined` when only the
1123
+ * hash could say, or when a runtime reassigns `__webpack_public_path__` — then the
1124
+ * global is the only thing that knows.
1125
+ * @returns {string | undefined} the settled public path
1126
+ */
1127
+ constantPublicPath() {
1128
+ const { publicPath } = this.outputOptions;
1129
+ if (
1130
+ publicPath === "auto" ||
1131
+ APIPlugin.usesRuntimePublicPathOverride(this.compilation)
1132
+ ) {
1133
+ return undefined;
1134
+ }
1135
+ if (typeof publicPath === "function") {
1136
+ const resolved = this._resolveHashIndependent(
1137
+ publicPath,
1138
+ this._publicPathShape()
1139
+ );
1140
+ return resolved === null ? undefined : resolved;
1141
+ }
1142
+ return publicPath.includes("[") ? undefined : publicPath;
1143
+ }
1144
+
1145
+ /**
1146
+ * Runtime keys grouped by the binaries they share, with what the entries of each
1147
+ * group asked for. Code generation runs once for runtimes a module hashes alike in,
1148
+ * and nothing in a binary's hash knows which loader will read it — so a binary two
1149
+ * runtimes reach carries one shape into both, and a third runtime sharing another
1150
+ * binary with either is pulled in after them. Only an entry names a loader; every
1151
+ * other chunk of the runtime is served by the one its entry asked for. Asked of the
1152
+ * same modules the loaders are created for, and only once per compilation.
1153
+ * @returns {WasmGroups} the grouping, and which groups fetch
1154
+ */
1155
+ _wasmGroups() {
1156
+ if (this._wasmGroupsValue === undefined) {
1157
+ const { chunkGraph, chunks, modules } = this.compilation;
1158
+ /** @type {Map<string, string>} */
1159
+ const parent = new Map();
1160
+ /**
1161
+ * @param {string} key runtime key
1162
+ * @returns {string} the key naming its group
1163
+ */
1164
+ const find = (key) => {
1165
+ let root = key;
1166
+ let seen = parent.get(root);
1167
+ while (seen !== undefined && seen !== root) {
1168
+ root = seen;
1169
+ seen = parent.get(root);
1170
+ }
1171
+ // Path compression keeps a long share chain from costing more than once.
1172
+ let walk = key;
1173
+ let next = parent.get(walk);
1174
+ while (next !== undefined && next !== root) {
1175
+ parent.set(walk, root);
1176
+ walk = next;
1177
+ next = parent.get(walk);
1178
+ }
1179
+ return root;
1180
+ };
1181
+ /** @type {string[]} */
1182
+ const keys = [];
1183
+ for (const module of modules) {
1184
+ if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
1185
+ keys.length = 0;
1186
+ for (const runtime of chunkGraph.getModuleRuntimes(module)) {
1187
+ forEachRuntime(runtime, (key) => {
1188
+ keys.push(/** @type {string} */ (key));
1189
+ });
1190
+ }
1191
+ for (const key of keys) if (!parent.has(key)) parent.set(key, key);
1192
+ // Every runtime this binary reaches answers with the first one.
1193
+ for (let i = 1; i < keys.length; i++) {
1194
+ parent.set(find(keys[i]), find(keys[0]));
1195
+ }
1196
+ }
1197
+ // Flattened once, so a lookup is a single `get` rather than a chain walk.
1198
+ for (const key of parent.keys()) parent.set(key, find(key));
1199
+ /**
1200
+ * @param {string} key a runtime key
1201
+ * @returns {string} the group it answers with, or itself when it shares nothing
1202
+ */
1203
+ const groupOf = (key) => {
1204
+ const group = parent.get(key);
1205
+ // An entry named "" makes "" a runtime key, so test absence, not a falsy value.
1206
+ return group === undefined ? key : group;
1207
+ };
1208
+ /** @type {Set<string>} */
1209
+ const fetching = new Set();
1210
+ /** @type {Map<string, boolean>} */
1211
+ const onlyFetching = new Map();
1212
+ for (const chunk of chunks) {
1213
+ if (!chunk.getEntryOptions()) continue;
1214
+ const fetches = this._chunkWasmLoading(chunk) === "fetch";
1215
+ forEachRuntime(chunk.runtime, (key) => {
1216
+ const group = groupOf(/** @type {string} */ (key));
1217
+ if (fetches) fetching.add(group);
1218
+ onlyFetching.set(group, onlyFetching.get(group) !== false && fetches);
1219
+ });
1220
+ }
1221
+ this._wasmGroupsValue = { groupOf, fetching, onlyFetching };
1222
+ }
1223
+ return this._wasmGroupsValue;
1224
+ }
1225
+
1226
+ /**
1227
+ * @param {RuntimeSpec} runtime the runtime being asked about
1228
+ * @returns {string[]} the wasm runtime groups it reaches
1229
+ */
1230
+ _wasmGroupsOf(runtime) {
1231
+ const { groupOf } = this._wasmGroups();
1232
+ /** @type {string[]} */
1233
+ const reached = [];
1234
+ forEachRuntime(runtime, (key) => {
1235
+ reached.push(groupOf(/** @type {string} */ (key)));
1236
+ });
1237
+ return reached;
1238
+ }
1239
+
1240
+ /**
1241
+ * Whether a chunk loads WebAssembly through `fetch`, which is the only loader the
1242
+ * public path reaches: `readFile` resolves the binary's name against the chunk it is
1243
+ * read from, exactly as a baked literal does, so a public path is irrelevant to it.
1244
+ * Answered per group rather than per chunk on purpose — a module's generated source
1245
+ * and the runtime module of every chunk holding it have to agree on the shape, and
1246
+ * they ask from opposite ends; one loader serves a whole group, so that is the finest
1247
+ * scope on which they can. Without a runtime the answer covers the compilation.
1248
+ * @param {RuntimeSpec=} runtime the runtime being asked about
1249
+ * @returns {boolean} true when a chunk of that runtime fetches its binaries
1250
+ */
1251
+ _anyWasmChunkFetches(runtime) {
1252
+ const { fetching } = this._wasmGroups();
1253
+ if (fetching.size === 0) return false;
1254
+ // Without a runtime to place it in there is nothing to narrow by, so any chunk
1255
+ // answers for all of them.
1256
+ if (runtime === undefined) return true;
1257
+ return this._wasmGroupsOf(runtime).some((group) => fetching.has(group));
1258
+ }
1259
+
1260
+ /**
1261
+ * Whether a public path needing a base can be spelled from the chunk every binary of
1262
+ * a runtime sits in — `fetch` reads it against the document, so a literal climbs back
1263
+ * there first. Per group, as `_anyWasmChunkFetches` is, since the two ends must agree.
1264
+ * @param {RuntimeSpec=} runtime the runtime being asked about
1265
+ * @returns {boolean} true when every binary of that group can be spelled
1266
+ */
1267
+ _wasmFetchAnchorIsKnown(runtime) {
1268
+ if (this._wasmAnchorKnownByGroup === undefined) {
1269
+ const { chunkGraph, modules } = this.compilation;
1270
+ const { groupOf, onlyFetching } = this._wasmGroups();
1271
+ /** @type {Map<string, boolean>} */
1272
+ const known = new Map();
1273
+ for (const module of modules) {
1274
+ if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
1275
+ // Probed through the very builder the generator runs, so the gate is
1276
+ // exact: a prefix it can spell — the per-asset deferrals included — is
1277
+ // one the group may bake. The probe name stands in for the binary's.
1278
+ const spellable =
1279
+ this._getAnalyzableFileSpecifier(
1280
+ module,
1281
+ /** @type {ChunkGraph} */ (chunkGraph),
1282
+ [["literal", "x"]],
1283
+ true
1284
+ ) !== null;
1285
+ for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
1286
+ forEachRuntime(moduleRuntime, (key) => {
1287
+ const group = groupOf(/** @type {string} */ (key));
1288
+ known.set(group, known.get(group) !== false && spellable);
1289
+ });
1290
+ }
1291
+ }
1292
+ // A group one entry reads with `readFile` cannot take a prefix meant for the
1293
+ // document, and only an entry names its loader.
1294
+ for (const [group, only] of onlyFetching) {
1295
+ if (!only) known.set(group, false);
1296
+ }
1297
+ this._wasmAnchorKnownByGroup = known;
1298
+ }
1299
+ const known = this._wasmAnchorKnownByGroup;
1300
+ // No runtime to place it in leaves every group answering, so one that cannot be
1301
+ // spelled speaks for all of them.
1302
+ if (runtime === undefined) {
1303
+ for (const value of known.values()) if (!value) return false;
1304
+ return known.size > 0;
1305
+ }
1306
+ return this._wasmGroupsOf(runtime).every(
1307
+ (group) => known.get(group) === true
1308
+ );
1309
+ }
1310
+
1311
+ supportTemplateLiteral() {
1312
+ return this.outputOptions.environment.templateLiteral;
1313
+ }
1314
+
1315
+ supportNodePrefixForCoreModules() {
1316
+ return this.outputOptions.environment.nodePrefixForCoreModules;
1317
+ }
1318
+
1319
+ /**
1320
+ * Renders node prefix for core module.
1321
+ * @param {string} mod a module
1322
+ * @returns {string} a module with `node:` prefix when supported, otherwise an original name
1323
+ */
1324
+ renderNodePrefixForCoreModule(mod) {
1325
+ return this.outputOptions.environment.nodePrefixForCoreModules
1326
+ ? `"node:${mod}"`
1327
+ : `"${mod}"`;
1328
+ }
1329
+
1330
+ /**
1331
+ * Renders return const when it is supported, otherwise let when supported, otherwise var.
1332
+ * @returns {"const" | "let" | "var"} return `const` when it is supported, otherwise `let` when supported, otherwise `var`
1333
+ */
1334
+ renderConst() {
1335
+ return this.supportsConst() ? "const" : this.supportsLet() ? "let" : "var";
1336
+ }
1337
+
1338
+ /**
1339
+ * Renders return let when it is supported, otherwise var.
1340
+ * @returns {"let" | "var"} return `let` when it is supported, otherwise `var`
1341
+ */
1342
+ renderLet() {
1343
+ return this.supportsLet() ? "let" : "var";
1344
+ }
1345
+
1346
+ /**
1347
+ * Returning function.
1348
+ * @param {string} returnValue return value
1349
+ * @param {string} args arguments
1350
+ * @returns {string} returning function
1351
+ */
1352
+ returningFunction(returnValue, args = "") {
1353
+ return this.supportsArrowFunction()
1354
+ ? `(${args}) => (${returnValue})`
1355
+ : `function(${args}) { return ${returnValue}; }`;
1356
+ }
1357
+
1358
+ /**
1359
+ * Returns basic function.
1360
+ * @param {string} args arguments
1361
+ * @param {string | string[]} body body
1362
+ * @returns {string} basic function
1363
+ */
1364
+ basicFunction(args, body) {
1365
+ return this.supportsArrowFunction()
1366
+ ? `(${args}) => {\n${Template.indent(body)}\n}`
1367
+ : `function(${args}) {\n${Template.indent(body)}\n}`;
1368
+ }
1369
+
1370
+ /**
1371
+ * Returns result expression.
1372
+ * @param {(string | { expr: string })[]} args args
1373
+ * @returns {string} result expression
1374
+ */
1375
+ concatenation(...args) {
1376
+ const len = args.length;
1377
+
1378
+ if (len === 2) return this._es5Concatenation(args);
1379
+ if (len === 0) return '""';
1380
+ if (len === 1) {
1381
+ return typeof args[0] === "string"
1382
+ ? JSON.stringify(args[0])
1383
+ : `"" + ${args[0].expr}`;
1384
+ }
1385
+ if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
1386
+
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)
1395
+
1396
+ let templateCost = 0;
1397
+ let concatenationCost = 0;
1398
+
1399
+ let lastWasExpr = false;
1400
+ for (const arg of args) {
1401
+ const isExpr = typeof arg !== "string";
1402
+ if (isExpr) {
1403
+ templateCost += 3;
1404
+ concatenationCost += lastWasExpr ? 1 : 4;
1405
+ }
1406
+ lastWasExpr = isExpr;
1407
+ }
1408
+ if (lastWasExpr) concatenationCost -= 3;
1409
+ if (typeof args[0] !== "string" && typeof args[1] === "string") {
1410
+ concatenationCost -= 3;
1411
+ }
1412
+
1413
+ if (concatenationCost <= templateCost) return this._es5Concatenation(args);
1414
+
1415
+ return `\`${args
1416
+ .map((arg) => (typeof arg === "string" ? arg : `\${${arg.expr}}`))
1417
+ .join("")}\``;
1418
+ }
1419
+
1420
+ /**
1421
+ * Returns result expression.
1422
+ * @param {(string | { expr: string })[]} args args (len >= 2)
1423
+ * @returns {string} result expression
1424
+ * @private
1425
+ */
1426
+ _es5Concatenation(args) {
1427
+ const str = args
1428
+ .map((arg) => (typeof arg === "string" ? JSON.stringify(arg) : arg.expr))
1429
+ .join(" + ");
1430
+
1431
+ // when the first two args are expression, we need to prepend "" + to force string
1432
+ // concatenation instead of number addition.
1433
+ return typeof args[0] !== "string" && typeof args[1] !== "string"
1434
+ ? `"" + ${str}`
1435
+ : str;
1436
+ }
1437
+
1438
+ /**
1439
+ * Expression function.
1440
+ * @param {string} expression expression
1441
+ * @param {string} args arguments
1442
+ * @returns {string} expression function code
1443
+ */
1444
+ expressionFunction(expression, args = "") {
1445
+ return this.supportsArrowFunction()
1446
+ ? `(${args}) => (${expression})`
1447
+ : `function(${args}) { ${expression}; }`;
1448
+ }
1449
+
1450
+ /**
1451
+ * Returns empty function code.
1452
+ * @returns {string} empty function code
430
1453
  */
431
1454
  emptyFunction() {
1455
+ // `x => {}` over `() => {}`: a minifier keeps the parameter, so the named
1456
+ // one is a byte shorter.
432
1457
  return this.supportsArrowFunction() ? "x => {}" : "function() {}";
433
1458
  }
434
1459
 
@@ -462,6 +1487,19 @@ class RuntimeTemplate {
462
1487
  return `typeof process !== "undefined" && typeof process.getBuiltinModule === "function" && ${getter}`;
463
1488
  }
464
1489
 
1490
+ /**
1491
+ * Renders a `then` callback calling `fn` with `args`. An arrow keeps the `this`
1492
+ * a method call gives; the bound form is shorter without arrows.
1493
+ * @param {string} fn callee, a member of `__webpack_require__` or itself
1494
+ * @param {string} args arguments
1495
+ * @returns {string} callback expression
1496
+ */
1497
+ deferredCall(fn, args) {
1498
+ return this.supportsArrowFunction()
1499
+ ? this.returningFunction(`${fn}(${args})`)
1500
+ : `${fn}.bind(${RuntimeGlobals.require}, ${args})`;
1501
+ }
1502
+
465
1503
  /**
466
1504
  * Renders an object-literal method, using method shorthand when supported
467
1505
  * and falling back to a `prop: function/arrow` property otherwise.
@@ -936,8 +1974,8 @@ class RuntimeTemplate {
936
1974
  const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
937
1975
 
938
1976
  const isModuleDeferred =
939
- (dependency instanceof getHarmonyImportDependency() ||
940
- dependency instanceof getImportDependency()) &&
1977
+ (dependency instanceof HarmonyImportDependency ||
1978
+ dependency instanceof ImportDependency) &&
941
1979
  ImportPhaseUtils.isDefer(dependency.phase) &&
942
1980
  !(/** @type {BuildMeta} */ (module.buildMeta).async);
943
1981
 
@@ -952,6 +1990,9 @@ class RuntimeTemplate {
952
1990
  (m) => chunkGraph.getModuleId(m)
953
1991
  ).filter((id) => id !== null);
954
1992
  if (asyncDeps.length) {
1993
+ runtimeRequirements.add(
1994
+ RuntimeGlobals.deferredModuleAsyncTransitiveDependencies
1995
+ );
955
1996
  if (header) {
956
1997
  appending = `.then(${this.basicFunction(
957
1998
  "",
@@ -967,7 +2008,10 @@ class RuntimeTemplate {
967
2008
  }(${JSON.stringify(asyncDeps)})`
968
2009
  )})`;
969
2010
  }
970
- appending += `.then(${RuntimeGlobals.makeDeferredNamespaceObject}.bind(${RuntimeGlobals.require}, ${comment}${idExpr}, ${mode}))`;
2011
+ appending += `.then(${this.deferredCall(
2012
+ RuntimeGlobals.makeDeferredNamespaceObject,
2013
+ `${comment}${idExpr}, ${mode}`
2014
+ )})`;
971
2015
  } else if (header) {
972
2016
  appending = `.then(${this.basicFunction(
973
2017
  "",
@@ -975,7 +2019,10 @@ class RuntimeTemplate {
975
2019
  )})`;
976
2020
  } else {
977
2021
  runtimeRequirements.add(RuntimeGlobals.require);
978
- appending = `.then(${RuntimeGlobals.makeDeferredNamespaceObject}.bind(${RuntimeGlobals.require}, ${comment}${idExpr}, ${mode}))`;
2022
+ appending = `.then(${this.deferredCall(
2023
+ RuntimeGlobals.makeDeferredNamespaceObject,
2024
+ `${comment}${idExpr}, ${mode}`
2025
+ )})`;
979
2026
  }
980
2027
  } else {
981
2028
  let fakeType = 16;
@@ -995,7 +2042,10 @@ class RuntimeTemplate {
995
2042
  )})`;
996
2043
  } else {
997
2044
  runtimeRequirements.add(RuntimeGlobals.require);
998
- appending = `.then(${RuntimeGlobals.require}.bind(${RuntimeGlobals.require}, ${comment}${idExpr}))`;
2045
+ appending = `.then(${this.deferredCall(
2046
+ RuntimeGlobals.require,
2047
+ `${comment}${idExpr}`
2048
+ )})`;
999
2049
  }
1000
2050
  break;
1001
2051
  case "dynamic":
@@ -1021,7 +2071,10 @@ class RuntimeTemplate {
1021
2071
  )})`;
1022
2072
  } else {
1023
2073
  runtimeRequirements.add(RuntimeGlobals.require);
1024
- appending = `.then(${RuntimeGlobals.require}.bind(${RuntimeGlobals.require}, ${comment}${idExpr}))`;
2074
+ appending = `.then(${this.deferredCall(
2075
+ RuntimeGlobals.require,
2076
+ `${comment}${idExpr}`
2077
+ )})`;
1025
2078
  }
1026
2079
  appending += `.then(${this.returningFunction(
1027
2080
  `${RuntimeGlobals.createFakeNamespaceObject}(m, ${fakeType})`,
@@ -1042,7 +2095,10 @@ class RuntimeTemplate {
1042
2095
  `${header}return ${returnExpression};`
1043
2096
  )})`;
1044
2097
  } else {
1045
- appending = `.then(${RuntimeGlobals.createFakeNamespaceObject}.bind(${RuntimeGlobals.require}, ${comment}${idExpr}, ${fakeType}))`;
2098
+ appending = `.then(${this.deferredCall(
2099
+ RuntimeGlobals.createFakeNamespaceObject,
2100
+ `${comment}${idExpr}, ${fakeType}`
2101
+ )})`;
1046
2102
  }
1047
2103
  }
1048
2104
  break;
@@ -1170,14 +2226,17 @@ class RuntimeTemplate {
1170
2226
  let importContent;
1171
2227
 
1172
2228
  const isModuleDeferred =
1173
- (dependency instanceof getHarmonyImportDependency() ||
1174
- dependency instanceof getImportDependency()) &&
2229
+ (dependency instanceof HarmonyImportDependency ||
2230
+ dependency instanceof ImportDependency) &&
1175
2231
  ImportPhaseUtils.isDefer(dependency.phase) &&
1176
- !(/** @type {BuildMeta} */ (module.buildMeta).async);
2232
+ !isAsyncExternal(module);
1177
2233
 
1178
2234
  if (isModuleDeferred) {
1179
2235
  /** @type {Set<Module>} */
1180
2236
  const outgoingAsyncModules = getOutgoingAsyncModules(moduleGraph, module);
2237
+ // A module deferring itself is already evaluating, so awaiting it here
2238
+ // would deadlock; forcing the namespace throws instead.
2239
+ outgoingAsyncModules.delete(originModule);
1181
2240
 
1182
2241
  importContent = `/* deferred harmony import */ ${optDeclaration}${importVar} = ${getOptimizedDeferredModule(
1183
2242
  moduleId,
@@ -1259,10 +2318,10 @@ class RuntimeTemplate {
1259
2318
  );
1260
2319
 
1261
2320
  const isModuleDeferred =
1262
- (dependency instanceof getHarmonyImportDependency() ||
1263
- dependency instanceof getImportDependency()) &&
2321
+ (dependency instanceof HarmonyImportDependency ||
2322
+ dependency instanceof ImportDependency) &&
1264
2323
  ImportPhaseUtils.isDefer(dependency.phase) &&
1265
- !(/** @type {BuildMeta} */ (module.buildMeta).async);
2324
+ !isAsyncExternal(module);
1266
2325
 
1267
2326
  if (defaultInterop) {
1268
2327
  // when the defaultInterop is used (when a ESM imports a CJS module),
@@ -1416,7 +2475,6 @@ class RuntimeTemplate {
1416
2475
  if (
1417
2476
  exportsType === "namespace" &&
1418
2477
  mangleableNamespace &&
1419
- this.compilation &&
1420
2478
  this.compilation.options.optimization.mangleExports
1421
2479
  ) {
1422
2480
  const materialized = this._materializedNamespaceObject({
@@ -1542,19 +2600,20 @@ class RuntimeTemplate {
1542
2600
  message,
1543
2601
  chunkName: block.chunkName
1544
2602
  });
1545
- // A `fetchPriority` hint rides on the runtime `ensureChunk(id, priority)` call;
1546
- // the analyzable literal `import()` can't carry it, so keep the runtime form.
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.
1547
2608
  const fetchPriority = chunkGroup.options.fetchPriority;
1548
2609
  if (chunks.length === 1) {
1549
- const analyzable = fetchPriority
1550
- ? null
1551
- : this._analyzableChunkImport(
1552
- chunks[0],
1553
- comment,
1554
- runtimeRequirements,
1555
- originModule,
1556
- chunkGraph
1557
- );
2610
+ const analyzable = this.analyzableChunkImport(
2611
+ chunks[0],
2612
+ comment,
2613
+ runtimeRequirements,
2614
+ originModule,
2615
+ chunkGraph
2616
+ );
1558
2617
  if (analyzable !== null) {
1559
2618
  return analyzable;
1560
2619
  }
@@ -1569,10 +2628,6 @@ class RuntimeTemplate {
1569
2628
  fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
1570
2629
  })`;
1571
2630
  } else if (chunks.length > 0) {
1572
- if (fetchPriority) {
1573
- runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
1574
- }
1575
-
1576
2631
  let needEnsureChunk = false;
1577
2632
  /**
1578
2633
  * Analyzable `import()` for a solely-owned JS chunk, else runtime ensureChunk.
@@ -1580,15 +2635,13 @@ class RuntimeTemplate {
1580
2635
  * @returns {string} require chunk id code
1581
2636
  */
1582
2637
  const requireChunkId = (chunk) => {
1583
- const analyzable = fetchPriority
1584
- ? null
1585
- : this._analyzableChunkImport(
1586
- chunk,
1587
- "",
1588
- runtimeRequirements,
1589
- originModule,
1590
- chunkGraph
1591
- );
2638
+ const analyzable = this.analyzableChunkImport(
2639
+ chunk,
2640
+ "",
2641
+ runtimeRequirements,
2642
+ originModule,
2643
+ chunkGraph
2644
+ );
1592
2645
  if (analyzable !== null) return analyzable;
1593
2646
  needEnsureChunk = true;
1594
2647
  return `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${
@@ -1598,12 +2651,32 @@ class RuntimeTemplate {
1598
2651
  const items = chunks.map(requireChunkId);
1599
2652
  if (needEnsureChunk) {
1600
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
+ }
1601
2658
  }
1602
2659
  return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
1603
2660
  }
1604
2661
  return `Promise.resolve(${comment.trim()})`;
1605
2662
  }
1606
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;
2675
+ }
2676
+ }
2677
+ return false;
2678
+ }
2679
+
1607
2680
  /**
1608
2681
  * For ESM module output, load a single statically-named chunk through the
1609
2682
  * `analyzableChunkImport` helper — a literal `import("./chunk.js")` other bundlers
@@ -1612,75 +2685,34 @@ class RuntimeTemplate {
1612
2685
  * @param {Chunk} chunk the chunk to load
1613
2686
  * @param {string} comment leading comment (chunk name / message)
1614
2687
  * @param {RuntimeRequirements} runtimeRequirements runtime requirements
1615
- * @param {Module=} originModule the module the `import()` is emitted into
1616
- * @param {ChunkGraph=} chunkGraph the chunk graph
2688
+ * @param {Module | undefined} originModule the module the `import()` is emitted into
2689
+ * @param {ChunkGraph} chunkGraph the chunk graph
1617
2690
  * @returns {string | null} the import expression, or `null`
1618
2691
  */
1619
- _analyzableChunkImport(
2692
+ analyzableChunkImport(
1620
2693
  chunk,
1621
2694
  comment,
1622
2695
  runtimeRequirements,
1623
2696
  originModule,
1624
2697
  chunkGraph
1625
2698
  ) {
1626
- const { outputOptions } = this;
2699
+ // `blockPromise` has already dropped any chunk without an id. Without an origin
2700
+ // there is nothing the specifier could be relative to.
1627
2701
  if (
1628
- !outputOptions.module ||
1629
- outputOptions.chunkFormat !== "module" ||
1630
- outputOptions.importFunctionName !== "import" ||
1631
- chunk.id === null ||
1632
2702
  !originModule ||
1633
- !chunkGraph
2703
+ !this.supportsAnalyzable("import", chunkGraph, originModule)
1634
2704
  ) {
1635
2705
  return null;
1636
2706
  }
1637
- // HMR wraps `ensureChunk` (`.e`) to track in-flight loads and relies on it being
1638
- // present in the runtime; the analyzable `import()` (`.ei`) replaces `.e` and would
1639
- // leave a lazy-compilation proxy's own `.e` call undefined, so keep the runtime form.
1640
- // A runtime `__webpack_public_path__` override likewise can't reach a baked literal.
1641
- if (
1642
- this.compilation.dependencyFactories.has(
1643
- getModuleHotAcceptDependency()
1644
- ) ||
1645
- getAPIPlugin().usesRuntimePublicPathOverride(this.compilation)
1646
- ) {
1647
- return null;
1648
- }
1649
- // A worker entry loads its own chunks through the worker runtime; keep that path.
1650
- for (const originChunk of chunkGraph.getModuleChunksIterable(
1651
- originModule
1652
- )) {
1653
- const entryOptions = originChunk.getEntryOptions();
1654
- if (entryOptions && entryOptions.worker) {
1655
- return null;
1656
- }
1657
- }
1658
- // Only a chunk that is loaded solely through this `import()` and holds pure JS:
1659
- // a shared chunk (splitChunks / module federation) or one with css/wasm/other
1660
- // assets needs the runtime's deduplication and per-type loaders, so keep it.
1661
- if (chunk.getNumberOfGroups() !== 1) {
1662
- return null;
1663
- }
1664
- // Prefetch/preload children (incl. CSS-only preload) are injected by the runtime
1665
- // `.f` handlers when the chunk loads, which the analyzable `import()` bypasses —
1666
- // keep the runtime form for them.
1667
- if (
1668
- chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
1669
- chunk.hasChildByOrder(chunkGraph, "preload", true) ||
1670
- chunk.hasChildByOrder(chunkGraph, "cssPreload", true)
1671
- ) {
1672
- return null;
1673
- }
1674
- for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
1675
- // Module federation (remote/shared/provide) loads through its own runtime.
1676
- if (FEDERATION_MODULE_TYPES.has(module.type)) {
1677
- return null;
1678
- }
1679
- for (const type of chunkGraph.getModuleSourceTypes(module)) {
1680
- if (type !== JAVASCRIPT_TYPE && type !== RUNTIME_TYPE) {
1681
- return null;
1682
- }
1683
- }
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
+ );
1684
2716
  }
1685
2717
  // Relative to the consuming chunk (`import.meta.url`) for `auto`, else an
1686
2718
  // absolute publicPath prefix.
@@ -1690,60 +2722,609 @@ class RuntimeTemplate {
1690
2722
  originModule,
1691
2723
  chunkGraph
1692
2724
  );
2725
+ if (specifier === null) {
2726
+ return null;
2727
+ }
1693
2728
  // `import()` needs a resolvable specifier — relative (`./`, `../`), absolute (`/`)
1694
- // or a URL scheme. A bare one (empty/relative publicPath) is treated as a package,
1695
- // so keep the runtime form. (`new URL(...)` callers accept bare, resolving vs base.)
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.
1696
2740
  if (
1697
- specifier === null ||
1698
- !/^"(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(specifier)
2741
+ chunk.hasChildByOrder(chunkGraph, "prefetch", true) ||
2742
+ chunk.hasChildByOrder(chunkGraph, "preload", true) ||
2743
+ chunk.hasChildByOrder(chunkGraph, "cssPreload", true) ||
2744
+ this._chunkLoadsBeyondJs(chunk, chunkGraph)
1699
2745
  ) {
1700
- return null;
2746
+ runtimeRequirements.add(RuntimeGlobals.ensureChunkHandlers);
1701
2747
  }
1702
- runtimeRequirements.add(RuntimeGlobals.analyzableChunkImport);
1703
2748
  // Drop-in for `ensureChunk(id)`: the literal `import()` can be statically
1704
2749
  // followed, the helper keeps webpack's install timing and deduplication.
1705
2750
  return `${RuntimeGlobals.analyzableChunkImport}(${JSON.stringify(
1706
2751
  chunk.id
1707
- )}, () => import(${comment}${specifier}))`;
2752
+ )}, ${this.returningFunction(`import(${comment}${resolvableSpecifier})`)})`;
2753
+ }
2754
+
2755
+ /**
2756
+ * Whether this chunk's hash settles before every chunk a stand-in would land in.
2757
+ * That is what makes a baked name readable from the consuming chunk's own hash, and
2758
+ * it is the tie-break that lets one direction of a cycle bake — `createHash` fixes a
2759
+ * total order, so the answer is the same in every build.
2760
+ * @param {Chunk} chunk the referenced chunk
2761
+ * @param {Iterable<Chunk>} targets the chunks the stand-in is written into
2762
+ * @returns {boolean} true when this one may bake and the others may not
2763
+ */
2764
+ _namesBeforeAll(chunk, targets) {
2765
+ if (chunk.id === null) return false;
2766
+ for (const target of targets) {
2767
+ if (!this._hashesBefore(chunk, target)) return false;
2768
+ }
2769
+ return true;
2770
+ }
2771
+
2772
+ /**
2773
+ * Whether `createHash` settles `chunk`'s hash before `target`'s: rounds first, then
2774
+ * id inside a round. The runtime round is ordered by references between its chunks
2775
+ * rather than by id, which the guard below sidesteps by reading no hash from one.
2776
+ * @param {Chunk} chunk the chunk whose hash would be read
2777
+ * @param {Chunk} target the chunk reading it
2778
+ * @returns {boolean} true when the hash exists by the time the target is hashed
2779
+ */
2780
+ _hashesBefore(chunk, target) {
2781
+ if (chunk === target || target.id === null) return false;
2782
+ // One settling after the compilation hash is read only by one settling later.
2783
+ // Before the marks exist, the answer is the one the marking will bring about.
2784
+ if (this._chunksBakingFullHash !== undefined) {
2785
+ const late = this._settlesLate(chunk);
2786
+ if (late !== this._settlesLate(target)) return !late;
2787
+ }
2788
+ const chunkGraph = /** @type {ChunkGraph} */ (this.compilation.chunkGraph);
2789
+ const round = hashRound(chunk, chunkGraph);
2790
+ const targetRound = hashRound(target, chunkGraph);
2791
+ if (round !== targetRound) return round < targetRound;
2792
+ // The runtime round is ordered by references between its chunks rather than by
2793
+ // id: an async entrypoint the target reaches is settled before it, which is the
2794
+ // only order that round fixes — a worker's chunk against the one spawning it.
2795
+ if (round === RUNTIME_HASH_ROUND) {
2796
+ for (const entrypoint of target.getAllReferencedAsyncEntrypoints()) {
2797
+ const { chunks } = entrypoint;
2798
+ if (chunks[chunks.length - 1] === chunk) return true;
2799
+ }
2800
+ return false;
2801
+ }
2802
+ return (
2803
+ compareIds(
2804
+ /** @type {ChunkId} */ (chunk.id),
2805
+ /** @type {ChunkId} */ (target.id)
2806
+ ) < 0
2807
+ );
2808
+ }
2809
+
2810
+ /**
2811
+ * Whether `createHash` settles this chunk's hash in the round that runs after the
2812
+ * compilation hash rather than in one of the four before it. Asked of the chunk
2813
+ * graph, which by then says so exactly: a chunk reaches that round by carrying a
2814
+ * full-hash runtime module, or by being put there by `_markChunksSettlingLate`.
2815
+ * @param {Chunk} chunk the chunk
2816
+ * @returns {boolean} true when its hash is taken last
2817
+ */
2818
+ _settlesLate(chunk) {
2819
+ return (
2820
+ /** @type {ChunkGraph} */
2821
+ (this.compilation.chunkGraph).getChunkFullHashModulesIterable(chunk) !==
2822
+ undefined
2823
+ );
1708
2824
  }
1709
2825
 
1710
2826
  /**
1711
- * Computes the `../`-path from the consuming module's chunk(s) back to the output
1712
- * root, so a chunk or asset can be referenced relative to `import.meta.url`. Returns
1713
- * `null` when the module lives in chunks of different depths (no single path works).
1714
- * @param {Module} module the consuming module
2827
+ * Whether this chunk's name is settled only once the compilation hash exists, because
2828
+ * the deferred pass writes that hash into its bytes. Marking it puts it in
2829
+ * `createHash`'s full-hash round, where the name is taken again afterwards — which is
2830
+ * what a chunk needing `__webpack_require__.p` gets for free, and what one that bakes
2831
+ * the same text instead has to be given.
2832
+ * @param {Chunk} chunk the chunk
2833
+ * @returns {boolean} true when it was marked
2834
+ */
2835
+ _bakesFullHash(chunk) {
2836
+ return (
2837
+ this._chunksBakingFullHash !== undefined &&
2838
+ this._chunksBakingFullHash.has(chunk)
2839
+ );
2840
+ }
2841
+
2842
+ /**
2843
+ * Finds the chunks whose bytes will carry the compilation hash and puts each in
2844
+ * `createHash`'s full-hash round, so its name is taken after that hash exists rather
2845
+ * than before. Read off what was generated rather than off what asked for it: a
2846
+ * module restored from the persistent cache carries a stand-in without being
2847
+ * generated again, and the token it carries is the whole question.
2848
+ * @returns {void}
2849
+ */
2850
+ _markChunksSettlingLate() {
2851
+ this._chunksBakingFullHash = new Set();
2852
+ const { compilation } = this;
2853
+ const chunkGraph = /** @type {ChunkGraph} */ (compilation.chunkGraph);
2854
+ const results = compilation.codeGenerationResults;
2855
+ if (results === undefined) return;
2856
+ /** @type {Map<Chunk, Set<string>>} */
2857
+ const namesBaked = new Map();
2858
+ this._namesBakedInto = namesBaked;
2859
+ /** @type {Map<string, Chunk>} */
2860
+ const chunksById = new Map();
2861
+ this._chunksByIdForFold = chunksById;
2862
+ for (const chunk of compilation.chunks) {
2863
+ if (chunk.id !== null) chunksById.set(String(chunk.id), chunk);
2864
+ }
2865
+ for (const chunk of compilation.chunks) {
2866
+ // One whose name does not move with its content has nothing to settle late.
2867
+ if (this._chunkNameIndependentOfContent(chunk)) continue;
2868
+ const demand = this._analyzableDemandOf(chunk, results, chunkGraph);
2869
+ if (demand === null) continue;
2870
+ if (demand.carriesFullHash) {
2871
+ this._chunksBakingFullHash.add(chunk);
2872
+ chunkGraph.attachFullHashModules(chunk, []);
2873
+ }
2874
+ if (demand.names.size > 0) namesBaked.set(chunk, demand.names);
2875
+ }
2876
+ // A late name makes the name it is baked into late too, and that one may be
2877
+ // baked further up — so this runs to a fixed point.
2878
+ let changed = true;
2879
+ while (changed) {
2880
+ changed = false;
2881
+ for (const [chunk, names] of namesBaked) {
2882
+ if (this._settlesLate(chunk)) continue;
2883
+ for (const id of names) {
2884
+ const other = chunksById.get(id);
2885
+ if (other === undefined || !this._settlesLate(other)) continue;
2886
+ chunkGraph.attachFullHashModules(chunk, []);
2887
+ changed = true;
2888
+ break;
2889
+ }
2890
+ }
2891
+ }
2892
+ }
2893
+
2894
+ /**
2895
+ * What the deferred pass will write into this chunk: whether any of it is built from
2896
+ * the compilation hash, and which chunks it names. Read off what was generated rather
2897
+ * than off what asked for it — a module restored from the persistent cache carries a
2898
+ * stand-in without being generated again, and the stand-in spells its own recipe.
2899
+ * @param {Chunk} chunk the chunk
2900
+ * @param {CodeGenerationResults} results this compilation's generated code
1715
2901
  * @param {ChunkGraph} chunkGraph the chunk graph
1716
- * @returns {string | null} relative undo path, or `null` when ambiguous
2902
+ * @returns {{ carriesFullHash: boolean, names: Set<string> } | null} what it writes,
2903
+ * or `null` where nothing is written
1717
2904
  */
1718
- _getModuleUndoPath(module, chunkGraph) {
2905
+ _analyzableDemandOf(chunk, results, chunkGraph) {
2906
+ const modules = chunkGraph.getChunkModulesIterableBySourceType(
2907
+ chunk,
2908
+ JAVASCRIPT_TYPE
2909
+ );
2910
+ if (modules === undefined) return null;
2911
+ let carriesFullHash = false;
2912
+ /** @type {Set<string>} */
2913
+ const names = new Set();
2914
+ let found = false;
2915
+ // Its own copy, since `lastIndex` is walked below; reset by the loop that ends it.
2916
+ const regexp = new RegExp(
2917
+ ANALYZABLE_TOKEN_REGEXP.source,
2918
+ ANALYZABLE_TOKEN_REGEXP.flags
2919
+ );
2920
+ for (const module of modules) {
2921
+ if (!results.has(module, chunk.runtime)) continue;
2922
+ const source = results.getSource(module, chunk.runtime, JAVASCRIPT_TYPE);
2923
+ const content = source && source.source();
2924
+ if (typeof content !== "string") continue;
2925
+ if (this._hasReservedFullHash(content)) {
2926
+ carriesFullHash = true;
2927
+ found = true;
2928
+ }
2929
+ /** @type {RegExpExecArray | null} */
2930
+ let match;
2931
+ while ((match = regexp.exec(content)) !== null) {
2932
+ const parts = RuntimeTemplate._readAnalyzableSpecifier(match[1]);
2933
+ if (parts === null) continue;
2934
+ found = true;
2935
+ for (const [kind, value] of parts) {
2936
+ if (FULL_HASH_PART_KINDS.has(kind)) {
2937
+ carriesFullHash = true;
2938
+ } else if (CHUNK_SPECIFIER_PART_KINDS.has(kind)) {
2939
+ names.add(String(value));
2940
+ }
2941
+ }
2942
+ }
2943
+ }
2944
+ return found ? { carriesFullHash, names } : null;
2945
+ }
2946
+
2947
+ /**
2948
+ * Whether everything in front of a chunk's filename is text the fold can account for.
2949
+ * `literal` is already in the chunk's modules, and `undo` is the `../` depth of the
2950
+ * asset it lands in, which `_chunkPlacement` reads off the filename template with the
2951
+ * hashes neutralized — so both are known while that chunk is hashed. A public path or
2952
+ * a template is not: it resolves against the compilation hash, which by then is still
2953
+ * being built out of this very hash.
2954
+ * @param {SpecifierPart[]} prefix what goes in front of the filename
2955
+ * @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
2956
+ * @returns {boolean} true when the filename is all that is left to account for
2957
+ */
2958
+ _foldsWholeName(prefix, chunks) {
2959
+ for (const [kind] of prefix) {
2960
+ if (kind === "literal") continue;
2961
+ if (kind !== "undo") return false;
2962
+ // An `undo` resolves to each asset's own depth, so every chunk it may land in
2963
+ // has to have one this can be sure of.
2964
+ for (const chunk of chunks) {
2965
+ if (this._chunkPlacement(chunk).undo === null) return false;
2966
+ }
2967
+ }
2968
+ return true;
2969
+ }
2970
+
2971
+ /**
2972
+ * Folds the names this chunk will have filled in by the deferred pass into its own
2973
+ * hash, so a name taken from that hash already stands for the bytes the fill leaves
2974
+ * behind — what lets a chunk named by `[chunkhash]`, or by `[contenthash]` with
2975
+ * nothing to repair it afterwards, hold a baked reference at all. The same thing
2976
+ * `RuntimeModule.dependentHash` does for the runtime form of the reference.
2977
+ *
2978
+ * Asked of every chunk whose name could move, and answered from the chunk graph
2979
+ * rather than from what was generated: a module restored from the persistent cache
2980
+ * carries a stand-in without being generated again. That over-counts a chunk whose
2981
+ * reference kept the runtime form, which costs a hash that changes when it needn't —
2982
+ * never a name that stays put while the bytes move.
2983
+ * Memoized because `createHash` asks twice — once for `chunk.hash` and once for
2984
+ * `chunk.contentHash` — and nothing an earlier chunk contributes moves between the
2985
+ * two, while the walk behind the answer is over everything the chunk reaches.
2986
+ * @param {Chunk} chunk the chunk being hashed
2987
+ * @param {Hash} hash its hash
2988
+ * @returns {void}
2989
+ */
2990
+ _foldAnalyzableNames(chunk, hash) {
2991
+ // Nothing to bring back in line where the name does not move with the content,
2992
+ // and folding there would move hashes that are settled correctly today.
2993
+ if (this._chunkNameIndependentOfContent(chunk)) return;
2994
+ // A chunk baking the compilation hash is asked twice with different answers —
2995
+ // once before that hash exists and once in the round that follows it — so the
2996
+ // memo would hand back the first one.
2997
+ const bakesFullHash = this._bakesFullHash(chunk);
2998
+ // A chunk settling late is asked once in its normal round and again in that one,
2999
+ // where what it reads has moved on, so the memo would hand back the first answer.
3000
+ const late = bakesFullHash || this._settlesLate(chunk);
3001
+ let folded = late ? undefined : this._foldedAnalyzableNames.get(chunk);
3002
+ if (folded === undefined) {
3003
+ const { compilation } = this;
3004
+ const { outputOptions } = compilation;
3005
+ // Read back off what was generated: walking the graph would fold in whatever
3006
+ // the group reaches, moving a split chunk that references nothing.
3007
+ const named = this._namesBakedInto && this._namesBakedInto.get(chunk);
3008
+ /** @type {Set<Chunk>} */
3009
+ const reachable = new Set();
3010
+ for (const id of named || []) {
3011
+ const referenced =
3012
+ this._chunksByIdForFold && this._chunksByIdForFold.get(id);
3013
+ if (referenced !== undefined) reachable.add(referenced);
3014
+ }
3015
+ // Its own `../` depth, which an `undo` stand-in in it resolves to. Constant per
3016
+ // chunk, but the bytes still move with it, so the name has to as well.
3017
+ const { undo } = this._chunkPlacement(chunk);
3018
+ const names = [undo === null ? "" : undo];
3019
+ // What the fill will write in place of every compilation-hash stand-in. Read
3020
+ // here rather than folded in as text elsewhere, because this is the one round
3021
+ // where it exists before the name is taken.
3022
+ if (bakesFullHash && compilation.hash !== undefined) {
3023
+ names.push(compilation.hash);
3024
+ }
3025
+ for (const referenced of reachable) {
3026
+ if (!this._hashesBefore(referenced, chunk)) continue;
3027
+ let byType = this._analyzableAssetNames.get(referenced);
3028
+ if (byType === undefined) {
3029
+ byType = new Map();
3030
+ this._analyzableAssetNames.set(referenced, byType);
3031
+ }
3032
+ for (const [contentHashType, naming] of CHUNK_ASSET_NAMING) {
3033
+ // No hash of that type is no asset of that type, so nothing names one.
3034
+ if (referenced.contentHash[contentHashType] === undefined) continue;
3035
+ let name = byType.get(contentHashType);
3036
+ if (name === undefined) {
3037
+ // The very call the fill makes, so what is folded in is what lands
3038
+ // there — a filename function included, which resolves to a name here
3039
+ // either way. Settled once: the hash it reads is, by `_hashesBefore`.
3040
+ name = compilation.getPath(
3041
+ naming.template(referenced, outputOptions),
3042
+ {
3043
+ chunk: referenced,
3044
+ runtime: referenced.runtime,
3045
+ contentHashType
3046
+ }
3047
+ );
3048
+ byType.set(contentHashType, name);
3049
+ }
3050
+ names.push(name);
3051
+ }
3052
+ }
3053
+ folded = names.join("\n");
3054
+ if (!late) this._foldedAnalyzableNames.set(chunk, folded);
3055
+ }
3056
+ if (folded !== "") hash.update(folded);
3057
+ }
3058
+
3059
+ /**
3060
+ * Drops what the fold cached, once `createHash` is done and nothing reads it again.
3061
+ * Replaced rather than emptied: a `WeakMap` has no `clear`.
3062
+ * @returns {void}
3063
+ */
3064
+ _releaseAnalyzableNameCaches() {
3065
+ this._foldedAnalyzableNames = new WeakMap();
3066
+ this._analyzableAssetNames = new WeakMap();
3067
+ this._namesBakedInto = undefined;
3068
+ this._chunksByIdForFold = undefined;
3069
+ }
3070
+
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
+ /**
3101
+ * The chunks a reference emitted into `module` is written into — the assets a
3102
+ * stand-in of ours would land in, and so the only ones a deferred fill could go
3103
+ * stale in. Resolved through concatenation first: it may have absorbed the module
3104
+ * that wrote the reference, and an absorbed one is in no chunk at all.
3105
+ * @param {Module} module the module a reference is emitted into
3106
+ * @param {ChunkGraph} chunkGraph the chunk graph
3107
+ * @returns {Iterable<Chunk>} the chunks holding it
3108
+ */
3109
+ _moduleChunks(module, chunkGraph) {
3110
+ return chunkGraph.getModuleChunksIterable(
3111
+ getConcatenatedModule().getChunkGraphModule(this.compilation, module)
3112
+ );
3113
+ }
3114
+
3115
+ /**
3116
+ * The `../` path back out of a public path that needs a base, which is where the
3117
+ * chunk loader puts what it fetches. Reads nothing but `output`, so it is answered
3118
+ * once: `""` where the path adds no depth, `null` where its shape is unknown.
3119
+ * @returns {string | null} the path back out of it
3120
+ */
3121
+ _publicPathClimb() {
3122
+ if (this._publicPathClimbText === undefined) {
3123
+ const shape = this._publicPathShape();
3124
+ const undo =
3125
+ shape === undefined
3126
+ ? null
3127
+ : getUndoPath(
3128
+ `${shape}x`,
3129
+ /** @type {string} */ (this.outputOptions.path),
3130
+ true
3131
+ );
3132
+ this._publicPathClimbText = undo === "./" ? "" : undo;
3133
+ }
3134
+ return this._publicPathClimbText;
3135
+ }
3136
+
3137
+ /**
3138
+ * Where a literal emitted into a chunk is read from: the `../` path back to the
3139
+ * output root, and whether the chunk loader fetched the chunk through
3140
+ * `output.publicPath` — such a chunk sits one public path below the root the runtime
3141
+ * resolves against, where an initial chunk the host fetched does not. Reads only the
3142
+ * chunk, so it is memoized on it and shared by every module in it.
3143
+ * @param {Chunk} chunk a chunk a reference is written into
3144
+ * @returns {Placement} where a literal in it is read from
3145
+ */
3146
+ _chunkPlacement(chunk) {
3147
+ const cached = this._placementByChunk.get(chunk);
3148
+ if (cached !== undefined) return cached;
1719
3149
  const { compilation } = this;
1720
3150
  const { outputOptions } = compilation;
1721
- const outputPath = /** @type {string} */ (outputOptions.path);
1722
- /** @type {string | null} */
1723
- let result = null;
1724
- let found = false;
1725
- for (const chunk of chunkGraph.getModuleChunksIterable(module)) {
1726
- const template = getJavascriptModulesPlugin().getChunkFilenameTemplate(
3151
+ const shape = this._chunkNameShape(chunk);
3152
+ const chunkName =
3153
+ shape === null
3154
+ ? null
3155
+ : compilation.getPath(shape, {
3156
+ chunk,
3157
+ runtime: chunk.runtime,
3158
+ contentHashType: JAVASCRIPT_TYPE
3159
+ });
3160
+ const placement = {
3161
+ // A name whose shape is unknown has an unknown depth, and the deferred pass
3162
+ // reads the real one off the asset it lands in.
3163
+ undo:
3164
+ chunkName === null
3165
+ ? null
3166
+ : getUndoPath(
3167
+ chunkName,
3168
+ /** @type {string} */ (outputOptions.path),
3169
+ true
3170
+ ),
3171
+ // A chunk in an initial group and an async one both is served at two urls,
3172
+ // one public path apart, so no one literal in it is right for both.
3173
+ loaded: chunk.isOnlyInitial() ? false : chunk.canBeInitial() ? null : true
3174
+ };
3175
+ this._placementByChunk.set(chunk, placement);
3176
+ return placement;
3177
+ }
3178
+
3179
+ /**
3180
+ * The chunk's filename with every hash neutralized, which is all the `../` depth
3181
+ * needs — hashes are not settled when this is asked and sit in the basename anyway.
3182
+ * A function is asked for the template it returns rather than handed to `getPath`,
3183
+ * which would have to resolve a placeholder in it against a hash that does not exist
3184
+ * yet; one that builds the name out of a hash itself gets a stand-in to build from.
3185
+ * @param {Chunk} chunk the chunk
3186
+ * @returns {string | null} the shape, or `null` where it cannot be known
3187
+ */
3188
+ _chunkNameShape(chunk) {
3189
+ const template = JavascriptModulesPlugin.getChunkFilenameTemplate(
3190
+ chunk,
3191
+ this.outputOptions
3192
+ );
3193
+ if (typeof template === "string") {
3194
+ return template.replace(HASH_IN_FILENAME_GLOBAL, "x");
3195
+ }
3196
+ try {
3197
+ return probeTemplateName(
3198
+ template,
1727
3199
  chunk,
1728
- outputOptions
1729
- );
1730
- const chunkName = compilation.getPath(
1731
- // Hashes aren't known during code generation and only sit in the basename
1732
- // (never a directory), so neutralize them — only the `../` depth matters.
1733
- typeof template === "string"
1734
- ? template.replace(HASH_IN_FILENAME_GLOBAL, "x")
1735
- : template,
1736
- { chunk, contentHashType: JAVASCRIPT_TYPE }
1737
- );
1738
- const undo = getUndoPath(chunkName, outputPath, true);
1739
- if (!found) {
1740
- result = undo;
1741
- found = true;
1742
- } else if (result !== undo) {
1743
- return null;
3200
+ JAVASCRIPT_TYPE,
3201
+ HASH_PROBE,
3202
+ true
3203
+ ).replace(HASH_IN_FILENAME_GLOBAL, "x");
3204
+ } catch (_error) {
3205
+ // Nothing to report: the naming call is given strictly less than this probe, so
3206
+ // one that throws here fails the build where the name is actually needed.
3207
+ return null;
3208
+ }
3209
+ }
3210
+
3211
+ /**
3212
+ * The `../` path from a chunk's own asset back to the output root. Hashes are
3213
+ * neutralized first: a runtime module is generated once to be hashed, before any
3214
+ * hash exists, so resolving one there throws — and `RuntimeModule.updateHash`
3215
+ * swallows that, pinning the module's hash to the message.
3216
+ * @param {Chunk} chunk the chunk whose asset holds the reference
3217
+ * @param {boolean} enforceRelative whether the answer keeps a leading `./`
3218
+ * @returns {string} the path back to the output root
3219
+ */
3220
+ chunkRootOutputDir(chunk, enforceRelative) {
3221
+ const shape = this._chunkNameShape(chunk);
3222
+ const name = this.compilation.getPath(
3223
+ shape === null
3224
+ ? JavascriptModulesPlugin.getChunkFilenameTemplate(
3225
+ chunk,
3226
+ this.outputOptions
3227
+ )
3228
+ : shape,
3229
+ { chunk, contentHashType: JAVASCRIPT_TYPE }
3230
+ );
3231
+ return getUndoPath(
3232
+ name,
3233
+ /** @type {string} */ (this.outputOptions.path),
3234
+ enforceRelative
3235
+ );
3236
+ }
3237
+
3238
+ /**
3239
+ * The one answer every chunk holding a reference agrees on, with either half `null`
3240
+ * where they do not — then no one literal is right for all of them.
3241
+ * @param {Module} module the module the reference is emitted into
3242
+ * @param {ChunkGraph} chunkGraph the chunk graph
3243
+ * @returns {Placement} where a literal in it is read from
3244
+ */
3245
+ _modulePlacement(module, chunkGraph) {
3246
+ return this._placementOf(this._moduleChunks(module, chunkGraph));
3247
+ }
3248
+
3249
+ /**
3250
+ * Whether each of these chunks is served one way — either the host fetched it or the
3251
+ * loader did, not both. One that is both is at two urls a public path apart with no
3252
+ * answer of its own, which no per-asset stand-in can supply.
3253
+ * @param {Iterable<Chunk>} chunks the chunks a literal is written into
3254
+ * @returns {boolean} true when each has an answer to give
3255
+ */
3256
+ _eachChunkServedOneWay(chunks) {
3257
+ for (const chunk of chunks) {
3258
+ if (this._chunkPlacement(chunk).loaded === null) return false;
3259
+ }
3260
+ return true;
3261
+ }
3262
+
3263
+ /**
3264
+ * The one answer every chunk in `chunks` agrees on, with either half `null` where
3265
+ * they do not.
3266
+ * @param {Iterable<Chunk>} chunks the chunks a literal is written into
3267
+ * @returns {Placement} where a literal in them is read from
3268
+ */
3269
+ _placementOf(chunks) {
3270
+ /** @type {Placement | undefined} */
3271
+ let first;
3272
+ /** @type {string | null} */
3273
+ let undo = null;
3274
+ /** @type {boolean | null} */
3275
+ let loaded = null;
3276
+ for (const chunk of chunks) {
3277
+ const own = this._chunkPlacement(chunk);
3278
+ if (first === undefined) {
3279
+ first = own;
3280
+ undo = own.undo;
3281
+ loaded = own.loaded;
3282
+ continue;
1744
3283
  }
3284
+ if (undo !== own.undo) undo = null;
3285
+ if (loaded !== own.loaded) loaded = null;
1745
3286
  }
1746
- return found ? result : null;
3287
+ if (first === undefined) return NO_PLACEMENT;
3288
+ // A module in one chunk — nearly all of them — hands back what that chunk said,
3289
+ // so the common answer costs no object of its own.
3290
+ return undo === first.undo && loaded === first.loaded
3291
+ ? first
3292
+ : { undo, loaded };
3293
+ }
3294
+
3295
+ /**
3296
+ * Static literal specifier (already quoted) for the `new URL(<here>, import.meta.url)`
3297
+ * a worker or worklet entry chunk bakes to, or `null` to keep the runtime form. The
3298
+ * gate and the build are asked together so every call site agrees on both — the
3299
+ * `new Worker(...)` emit, and the resource hint `ResourceHintPlugin` spells for it.
3300
+ * @param {string | undefined} overridePublicPath a `publicPath` set on the worker itself
3301
+ * @param {Chunk} chunk the worker's entry chunk
3302
+ * @param {Module} module the module the reference is emitted into
3303
+ * @param {ChunkGraph} chunkGraph the chunk graph
3304
+ * @param {RuntimeRequirements} runtimeRequirements what the consuming chunk needs
3305
+ * @returns {string | null} a quoted literal, or `null` to fall back
3306
+ */
3307
+ getAnalyzableWorkerUrl(
3308
+ overridePublicPath,
3309
+ chunk,
3310
+ module,
3311
+ chunkGraph,
3312
+ runtimeRequirements
3313
+ ) {
3314
+ // Without an id nothing can name the chunk in a stand-in.
3315
+ if (
3316
+ chunk.id === null ||
3317
+ !this.supportsAnalyzable("url", chunkGraph, module)
3318
+ ) {
3319
+ return null;
3320
+ }
3321
+ return this._getAnalyzableChunkSpecifier(
3322
+ overridePublicPath,
3323
+ chunk,
3324
+ module,
3325
+ chunkGraph,
3326
+ runtimeRequirements
3327
+ );
1747
3328
  }
1748
3329
 
1749
3330
  /**
@@ -1752,47 +3333,583 @@ class RuntimeTemplate {
1752
3333
  * statically — a content hash in the filename, or a dynamic/templated publicPath.
1753
3334
  * @param {string | undefined} overridePublicPath per-dependency public path (wins over `output.publicPath`)
1754
3335
  * @param {Chunk} chunk the chunk to reference
1755
- * @param {Module} consumingModule the module the reference is emitted into
3336
+ * @param {Module | undefined} consumingModule the module the reference is emitted
3337
+ * into, or `undefined` when `consumingChunks` names where it goes instead
1756
3338
  * @param {ChunkGraph} chunkGraph the chunk graph
1757
- * @returns {string | null} a JS string literal, or `null` to fall back to the runtime form
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
+ * @param {Chunk[]=} consumingChunks the chunks the reference is written into, where
3342
+ * they are known without a module to read them from
3343
+ * @param {string=} sourceType which half of the chunk is named — its javascript by
3344
+ * default, or its stylesheet
3345
+ * @returns {string | null} a JS string literal or expression, or `null` to fall back to the runtime form
1758
3346
  */
1759
3347
  _getAnalyzableChunkSpecifier(
1760
3348
  overridePublicPath,
1761
3349
  chunk,
1762
3350
  consumingModule,
1763
- chunkGraph
3351
+ chunkGraph,
3352
+ runtimeRequirements,
3353
+ consumingChunks,
3354
+ sourceType = JAVASCRIPT_TYPE
1764
3355
  ) {
1765
3356
  const { compilation } = this;
1766
3357
  const { outputOptions } = compilation;
1767
- const filenameTemplate =
1768
- getJavascriptModulesPlugin().getChunkFilenameTemplate(
1769
- chunk,
1770
- outputOptions
3358
+ const naming = CHUNK_ASSET_NAMING.get(sourceType);
3359
+ // Nothing here names this type's asset, so nothing can spell where it will be.
3360
+ if (naming === undefined) return null;
3361
+ const template = this._resolveChunkFilenameTemplate(
3362
+ naming.template(chunk, outputOptions),
3363
+ chunk,
3364
+ sourceType
3365
+ );
3366
+ if (template === null) return null;
3367
+ // A hashed name is settled long after this code is generated, so a stand-in is
3368
+ // emitted and filled in once the hash exists.
3369
+ const deferred = template === undefined || HASH_IN_FILENAME.test(template);
3370
+ // 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.
3374
+ const chunks =
3375
+ consumingChunks ||
3376
+ 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
+ });
3411
+ /**
3412
+ * @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
3415
+ */
3416
+ const specifier = (prefix) => {
3417
+ if (!deferred) {
3418
+ const text = literalText(prefix);
3419
+ if (text !== null) return toJsStringLiteral(text + filename);
3420
+ }
3421
+ if (!canReserve && !(canFold && this._foldsWholeName(prefix, chunks))) {
3422
+ return cannotReserve();
3423
+ }
3424
+ return toJsStringLiteral(
3425
+ this._reserveAnalyzableSpecifier([
3426
+ ...prefix,
3427
+ [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
3428
+ ])
3429
+ );
3430
+ };
3431
+ if (overridePublicPath) {
3432
+ const resolved = this._resolvePublicPathPrefix(
3433
+ overridePublicPath,
3434
+ consumingModule,
3435
+ chunks
1771
3436
  );
3437
+ return resolved === null ? null : specifier(resolved);
3438
+ }
3439
+ const { publicPath } = outputOptions;
3440
+ if (publicPath === "auto") {
3441
+ const { undo } = this._placementOf(chunks);
3442
+ if (undo !== null) return specifier([["literal", undo]]);
3443
+ // Different depths — no one `../` path is right for every asset the reference
3444
+ // 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)}`;
3454
+ }
3455
+ const prefix = this._analyzablePathPrefix(
3456
+ consumingModule,
3457
+ chunkGraph,
3458
+ chunks
3459
+ );
3460
+ return prefix === null ? null : specifier(prefix);
3461
+ }
3462
+
3463
+ /**
3464
+ * The parts that go in front of a name so a literal read from the chunk holding it
3465
+ * reaches what the runtime would. A public path needing no base is the whole answer.
3466
+ * One that needs a base is read from the output root, so the `../` path back there
3467
+ * comes first — and is the whole answer again where the chunk loader fetched this
3468
+ * chunk through that same path, since climbing out of it only to spell it again
3469
+ * names the place it started from. An entry `baseUri` sits between the two, so
3470
+ * there both are written. Never asked of an `auto` public path, which is no path
3471
+ * to walk back over.
3472
+ * @param {Module | undefined} module the module the reference is emitted into
3473
+ * @param {ChunkGraph} chunkGraph the chunk graph
3474
+ * @param {Iterable<Chunk>} chunks the chunks a stand-in would be written into
3475
+ * @param {string=} relativeBase an entry `baseUri` read against the output root
3476
+ * @returns {SpecifierPart[] | null} the parts, or `null` having recorded why not
3477
+ */
3478
+ _analyzablePathPrefix(module, chunkGraph, chunks, relativeBase) {
3479
+ const publicPath = /** @type {PublicPath} */ (
3480
+ this.outputOptions.publicPath
3481
+ );
3482
+ const shape = this._publicPathShape();
3483
+ if (shape === undefined) return null;
3484
+ const resolve = () =>
3485
+ this._resolvePublicPathPrefix(publicPath, module, chunks);
3486
+ if (isBaseIndependent(shape)) return resolve();
3487
+ const { undo, loaded } = this._placementOf(chunks);
3488
+ // What a chunk the loader fetched climbs back out of. One of no depth leaves
3489
+ // nothing to climb, and then both answers put the same text in front.
3490
+ const served = this._publicPathClimb();
3491
+ const climb =
3492
+ loaded === null ? (served === "" ? "" : null) : loaded ? served : "";
3493
+ /** @type {SpecifierPart[]} */
3494
+ const head = [undo === null ? ["undo", ""] : ["literal", undo]];
3495
+ if (climb === null) {
3496
+ // Each knows its own answer, so the fill asks per asset — where each has one,
3497
+ // and where nothing else goes between the two shapes.
3498
+ if (relativeBase !== undefined || !this._eachChunkServedOneWay(chunks)) {
3499
+ return this._analyzableBailout(module, SERVED_BAILOUT, null);
3500
+ }
3501
+ return [...head, ["unserved", ""]];
3502
+ }
3503
+ if (climb !== "" && relativeBase === undefined) return head;
3504
+ const resolved = resolve();
3505
+ if (resolved === null) return null;
3506
+ if (climb !== "") head.push(["literal", climb]);
3507
+ if (relativeBase !== undefined) head.push(["literal", relativeBase]);
3508
+ head.push(...rootedParts(resolved));
3509
+ return head;
3510
+ }
3511
+
3512
+ /**
3513
+ * What a public path puts in front of a filename, as the parts it is built from.
3514
+ * A plain one is literal text. A templated one is resolved as far as code
3515
+ * generation can, leaving the compilation hash it may carry as a stand-in exactly
3516
+ * as `PublicPathRuntimeModule` resolves the same string once that hash exists — and
3517
+ * a hash re-encoded to another digest, which no stand-in can carry, is handed to
3518
+ * the deferred pass whole instead. A function is called for its value rather than
3519
+ * read as a template, so one whose answer moves with the hash is called again there.
3520
+ * @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
+ * @returns {SpecifierPart[] | null} the parts, or `null` when it cannot be known
3525
+ */
3526
+ _resolvePublicPathPrefix(publicPath, module, chunks) {
3527
+ if (typeof publicPath === "function") {
3528
+ // One that answers nothing to a probe cannot be placed, absolute or not.
3529
+ if (this._publicPathShape() === undefined) return null;
3530
+ const resolved = this._resolveHashIndependent(
3531
+ publicPath,
3532
+ this._publicPathShape()
3533
+ );
3534
+ if (resolved !== null) return [["literal", resolved]];
3535
+ // Called again by the fill against the compilation hash, so what it answers
3536
+ // there is that hash by another name.
3537
+ return this._canDeferOrBakeFullHash(true, chunks, module)
3538
+ ? [["publicPath", ""]]
3539
+ : null;
3540
+ }
3541
+ if (!publicPath.includes("[")) return [["literal", publicPath]];
3542
+ // A re-encoded digest cannot be spelled by a stand-in, so it stays a template.
3543
+ if (getTemplatedPathPlugin().usesFullHashDigest(publicPath)) {
3544
+ return this._canDeferOrBakeFullHash(true, chunks, module)
3545
+ ? [["template", publicPath]]
3546
+ : null;
3547
+ }
3548
+ const literal = this.compilation.getPath(
3549
+ publicPath,
3550
+ this._deferredFullHashPathData()
3551
+ );
3552
+ return this._canDeferOrBakeFullHash(
3553
+ this._hasReservedFullHash(literal),
3554
+ chunks,
3555
+ module
3556
+ )
3557
+ ? [["literal", literal]]
3558
+ : null;
3559
+ }
3560
+
3561
+ /**
3562
+ * `output.publicPath` as the text it will have the shape of — a function's answer to
3563
+ * a stand-in hash, which says whether it is absolute even when its value is not
3564
+ * settled yet. `"auto"` reads as the empty string, which needs a base and so takes
3565
+ * the path that needs no answer; a function that answers nothing says nothing about
3566
+ * its shape either, and nothing may be built on it.
3567
+ * @returns {string | undefined} the shape of the public path
3568
+ */
3569
+ _publicPathShape() {
3570
+ if (this._publicPathShapeText === undefined) {
3571
+ const { publicPath } = this.outputOptions;
3572
+ if (typeof publicPath !== "function") {
3573
+ this._publicPathShapeText = publicPath === "auto" ? "" : publicPath;
3574
+ } else {
3575
+ try {
3576
+ this._publicPathShapeText = this.compilation.getPath(publicPath, {
3577
+ hash: HASH_PROBE
3578
+ });
3579
+ } catch (_error) {
3580
+ this._publicPathShapeText = false;
3581
+ }
3582
+ }
3583
+ }
3584
+ return this._publicPathShapeText === false
3585
+ ? undefined
3586
+ : this._publicPathShapeText;
3587
+ }
3588
+
3589
+ /**
3590
+ * A path built by a function, resolved to the value it will have — or `null` when
3591
+ * it moves with the compilation hash, which code generation does not know.
3592
+ * @param {import("./TemplatedPathPlugin").TemplatePathFn<EXPECTED_ANY>} fn the function
3593
+ * @param {string | undefined} value its answer to the first probe, or `undefined`
3594
+ * when it answered nothing
3595
+ * @returns {string | null} the settled value, or `null` when it is hash-dependent
3596
+ */
3597
+ _resolveHashIndependent(fn, value) {
3598
+ // The shape is this function's answer to the first probe, already taken and
3599
+ // memoized, so only the second one is new here.
3600
+ if (value === undefined) return null;
3601
+ try {
3602
+ return this.compilation.getPath(fn, { hash: HASH_PROBE_ALTERNATE }) ===
3603
+ value
3604
+ ? value
3605
+ : null;
3606
+ } catch (_error) {
3607
+ // One that needs more than a hash can't be resolved here.
3608
+ return null;
3609
+ }
3610
+ }
3611
+
3612
+ /**
3613
+ * Static literal specifier (already quoted) for a `new URL(<here>, import.meta.url)`
3614
+ * pointing at an emitted file — an asset, or a wasm binary. The base is the asset the
3615
+ * reference sits in; the runtime form resolves against the output root instead, so a
3616
+ * public path that needs a base is put behind the `../` path back to that root rather
3617
+ * than baked as the whole prefix.
3618
+ * @param {Module} module the module the reference is emitted into
3619
+ * @param {ChunkGraph} chunkGraph the chunk graph
3620
+ * @param {SpecifierPart[]} file the emitted file's name, relative to the output root
3621
+ * @param {boolean} bakePublicPath whether the public path belongs in the literal
3622
+ * @param {string=} relativeBase an entry `baseUri` the runtime reads against the
3623
+ * chunk, so it belongs between the path back to the output root and the public path
3624
+ * @returns {string | null} a quoted literal, or `null` to fall back
3625
+ */
3626
+ _getAnalyzableFileSpecifier(
3627
+ module,
3628
+ chunkGraph,
3629
+ file,
3630
+ bakePublicPath,
3631
+ relativeBase
3632
+ ) {
3633
+ const { publicPath } = this.outputOptions;
3634
+ const chunks = this._moduleChunks(module, chunkGraph);
3635
+ if (bakePublicPath && publicPath !== "auto") {
3636
+ const prefix = this._analyzablePathPrefix(
3637
+ module,
3638
+ chunkGraph,
3639
+ chunks,
3640
+ relativeBase
3641
+ );
3642
+ if (prefix === null) return null;
3643
+ return this._specifierOf([...prefix, ...file], chunks, module);
3644
+ }
3645
+ // No public path to place it against, so the `../` path back to the output root
3646
+ // is the whole prefix. Different depths — no one is right for every asset the
3647
+ // reference is emitted into, so the deferred pass builds each asset's own.
3648
+ const { undo } = this._modulePlacement(module, chunkGraph);
3649
+ /** @type {SpecifierPart[]} */
3650
+ const parts = [undo === null ? ["undo", ""] : ["literal", undo]];
3651
+ if (relativeBase !== undefined) parts.push(["literal", relativeBase]);
3652
+ parts.push(...file);
3653
+ return this._specifierOf(parts, chunks, module);
3654
+ }
3655
+
3656
+ /**
3657
+ * 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
3660
+ * and the plugin declaring what it needs ask this, so the two always agree. The
3661
+ * runtime hands an absolute url string to `link.href`, and so does this — the browser
3662
+ * 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.
3665
+ * @param {Chunk} runtimeChunk the chunk holding the stylesheet loader
3666
+ * @param {ChunkGraph} chunkGraph the chunk graph
3667
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3668
+ * @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
3670
+ */
3671
+ analyzableCssChunkUrls(
3672
+ runtimeChunk,
3673
+ chunkGraph,
3674
+ runtimeRequirements,
3675
+ consumingModule
3676
+ ) {
3677
+ const { chunkHasCss } = getCssModulesPlugin();
3678
+ // An initial stylesheet is already in the document, but the hot path re-loads it
3679
+ // by id like any other, so it needs a url here too.
3680
+ const reachable = new Set([
3681
+ ...runtimeChunk.getAllReferencedChunks(),
3682
+ ...runtimeChunk.getAllInitialChunks()
3683
+ ]);
3684
+ const chunks = [];
3685
+ for (const chunk of reachable) {
3686
+ if (chunkHasCss(chunk, chunkGraph)) chunks.push(chunk);
3687
+ }
3688
+ return this._analyzableChunkUrls(
3689
+ chunks,
3690
+ chunkGraph,
3691
+ consumingModule,
3692
+ [runtimeChunk],
3693
+ CSS_TYPE,
3694
+ runtimeRequirements
3695
+ );
3696
+ }
3697
+
3698
+ /**
3699
+ * Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
3700
+ * 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
3703
+ * them and the plugin declaring what it needs ask this, so the two always agree.
3704
+ * @param {Chunk} runtimeChunk the chunk holding the hint handlers
3705
+ * @param {ChunkGraph} chunkGraph the chunk graph
3706
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
3707
+ * @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
3709
+ */
3710
+ analyzableChunkScriptUrls(
3711
+ runtimeChunk,
3712
+ chunkGraph,
3713
+ runtimeRequirements,
3714
+ consumingModule
3715
+ ) {
3716
+ // Only a child some order names reaches a handler. Every order counts, not the
3717
+ // two that reach javascript today: an unknown one costs bytes, not a missing url.
3718
+ const orders = runtimeChunk.getChildIdsByOrdersMap(
3719
+ chunkGraph,
3720
+ true,
3721
+ JavascriptModulesPlugin.chunkHasJs
3722
+ );
3723
+ /** @type {Set<ChunkId>} */
3724
+ const hinted = new Set();
3725
+ for (const byParent of Object.values(orders)) {
3726
+ for (const ids of Object.values(byParent)) {
3727
+ for (const id of ids) hinted.add(id);
3728
+ }
3729
+ }
3730
+ /** @type {Chunk[]} */
3731
+ const chunks = [];
3732
+ for (const chunk of runtimeChunk.getAllReferencedChunks()) {
3733
+ if (hinted.has(/** @type {ChunkId} */ (chunk.id))) chunks.push(chunk);
3734
+ }
3735
+ return this._analyzableChunkUrls(
3736
+ chunks,
3737
+ chunkGraph,
3738
+ consumingModule,
3739
+ [runtimeChunk],
3740
+ JAVASCRIPT_TYPE,
3741
+ runtimeRequirements
3742
+ );
3743
+ }
3744
+
3745
+ /**
3746
+ * 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.
3749
+ * @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
3750
+ * @param {ChunkGraph} chunkGraph the chunk graph
3751
+ * @param {Module | undefined} consumingModule the runtime module, where one exists to report against
3752
+ * @param {Chunk[]} consumingChunks the chunks the urls are written into
3753
+ * @param {string} sourceType which asset of each chunk to name
3754
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
3755
+ * @returns {AnalyzableChunkUrls | null} the urls, or `null` to keep the runtime form
3756
+ */
3757
+ _analyzableChunkUrls(
3758
+ chunks,
3759
+ chunkGraph,
3760
+ consumingModule,
3761
+ consumingChunks,
3762
+ sourceType,
3763
+ runtimeRequirements
3764
+ ) {
3765
+ // A map written now cannot answer for whatever id an update names, so it yields
3766
+ // to HMR — analyzable output is what ships.
1772
3767
  if (
1773
- typeof filenameTemplate !== "string" ||
1774
- HASH_IN_FILENAME.test(filenameTemplate)
3768
+ runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers) ||
3769
+ !this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)
1775
3770
  ) {
1776
3771
  return null;
1777
3772
  }
1778
- const filename = compilation.getPath(filenameTemplate, {
1779
- chunk,
1780
- contentHashType: JAVASCRIPT_TYPE
1781
- });
1782
- if (overridePublicPath) {
1783
- return overridePublicPath.includes("[")
1784
- ? null
1785
- : toJsStringLiteral(overridePublicPath + filename);
3773
+ /** @type {Map<ChunkId, string>} */
3774
+ const urls = new Map();
3775
+ let complete = true;
3776
+ for (const chunk of chunks) {
3777
+ if (chunk.id === null) continue;
3778
+ const specifier = this._getAnalyzableChunkSpecifier(
3779
+ undefined,
3780
+ chunk,
3781
+ consumingModule,
3782
+ chunkGraph,
3783
+ undefined,
3784
+ consumingChunks,
3785
+ sourceType
3786
+ );
3787
+ // `_getAnalyzableChunkSpecifier` has already recorded why.
3788
+ if (specifier === null) {
3789
+ complete = false;
3790
+ continue;
3791
+ }
3792
+ urls.set(chunk.id, `${this.importMetaUrl(specifier)}.href`);
1786
3793
  }
1787
- const { publicPath } = outputOptions;
1788
- if (publicPath === "auto") {
1789
- const undo = this._getModuleUndoPath(consumingModule, chunkGraph);
1790
- return undo === null ? null : toJsStringLiteral(undo + filename);
3794
+ return urls.size > 0 ? { urls, complete } : null;
3795
+ }
3796
+
3797
+ /**
3798
+ * Static `new URL(<file>, import.meta.url)` for the binary emitted for an async wasm
3799
+ * module. Only called when `supportsAnalyzable("wasm")` holds.
3800
+ * @param {Module} module the async wasm module
3801
+ * @param {ChunkGraph} chunkGraph the chunk graph
3802
+ * @param {RuntimeSpec} runtime the runtime
3803
+ * @param {RuntimeRequirements} runtimeRequirements runtime requirements
3804
+ * @returns {string} expression evaluating to the binary's URL
3805
+ */
3806
+ getAnalyzableWasmUrl(module, chunkGraph, runtime, runtimeRequirements) {
3807
+ const { compilation } = this;
3808
+ const template = /** @type {string} */ (
3809
+ this.outputOptions.webassemblyModuleFilename
3810
+ );
3811
+ // The module's own hash and id are settled here, the compilation's is not — and
3812
+ // a placeholder nothing answers is left in the name, so what comes back is either
3813
+ // the final name or a template carrying only `[fullhash]`.
3814
+ const filename = compilation.getPath(template, {
3815
+ module,
3816
+ runtime,
3817
+ chunkGraph
3818
+ });
3819
+ // Only a fetched binary carries the public path: `readFile` addresses it relative
3820
+ // to the chunk anyway. One needing a base is spelled as an asset url is.
3821
+ const specifier = this._getAnalyzableFileSpecifier(
3822
+ module,
3823
+ chunkGraph,
3824
+ [[filename.includes("[") ? "template" : "literal", filename]],
3825
+ this._wasmModuleFetches(module, chunkGraph)
3826
+ );
3827
+ if (specifier !== null) return this.importMetaUrl(specifier);
3828
+ // No bundler follows a concatenation, but this still sheds the module id and
3829
+ // hash the runtime form would need.
3830
+ runtimeRequirements.add(RuntimeGlobals.publicPath);
3831
+ return this.importMetaUrl(
3832
+ `${RuntimeGlobals.publicPath} + ${toJsStringLiteral(
3833
+ compilation.getPath(template, {
3834
+ module,
3835
+ runtime,
3836
+ chunkGraph,
3837
+ ...this._deferredFullHashPathData()
3838
+ })
3839
+ )}`
3840
+ );
3841
+ }
3842
+
3843
+ /**
3844
+ * The chunk filename template as a plain string. A function is called twice, with
3845
+ * a different stand-in hash each time; disagreeing answers mean the name depends on
3846
+ * a hash, which is not knowable during code generation, so it is left to the
3847
+ * deferred pass to ask again once the hashes are settled.
3848
+ * @param {ChunkFilenameTemplate} filenameTemplate the configured template
3849
+ * @param {Chunk} chunk the chunk being referenced
3850
+ * @param {string} contentHashType which of the chunk's hashes the name reads
3851
+ * @returns {string | undefined | null} the template, `undefined` to defer, or
3852
+ * `null` to fall back
3853
+ */
3854
+ _resolveChunkFilenameTemplate(filenameTemplate, chunk, contentHashType) {
3855
+ if (typeof filenameTemplate === "string") return filenameTemplate;
3856
+ try {
3857
+ // Everything the naming call is given except the hashes, so only a hash can
3858
+ // make the two answers differ.
3859
+ const template = probeTemplateName(
3860
+ filenameTemplate,
3861
+ chunk,
3862
+ contentHashType,
3863
+ HASH_PROBE,
3864
+ true
3865
+ );
3866
+ const probe = probeTemplateName(
3867
+ filenameTemplate,
3868
+ chunk,
3869
+ contentHashType,
3870
+ HASH_PROBE_ALTERNATE,
3871
+ false
3872
+ );
3873
+ return template === probe ? template : undefined;
3874
+ } catch (_error) {
3875
+ // Nothing to report: the probe is given strictly more than the naming call,
3876
+ // so one that throws here throws there too and fails the build regardless.
3877
+ return null;
1791
3878
  }
1792
- if (typeof publicPath === "string" && !publicPath.includes("[")) {
1793
- return toJsStringLiteral(publicPath + filename);
3879
+ }
3880
+
3881
+ /**
3882
+ * Whether `module`'s binary is read through `fetch`, the one loader the public path
3883
+ * reaches. Asked of its runtimes, not its chunks: only an entry names a loader.
3884
+ * @param {Module} module the async wasm module
3885
+ * @param {ChunkGraph} chunkGraph the chunk graph
3886
+ * @returns {boolean} true when every runtime reaching it fetches
3887
+ */
3888
+ _wasmModuleFetches(module, chunkGraph) {
3889
+ const { onlyFetching } = this._wasmGroups();
3890
+ let placed = false;
3891
+ for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
3892
+ for (const group of this._wasmGroupsOf(moduleRuntime)) {
3893
+ placed = true;
3894
+ if (!onlyFetching.get(group)) return false;
3895
+ }
1794
3896
  }
1795
- return null;
3897
+ // In no runtime at all nothing named a loader, so `output` answers.
3898
+ return placed || this.outputOptions.wasmLoading === "fetch";
3899
+ }
3900
+
3901
+ /**
3902
+ * The loader a chunk's WebAssembly is read with. An entry names one, and every
3903
+ * other chunk of the runtime is served by the one its entry asked for — so one
3904
+ * that is no entry answers with what `output` says.
3905
+ * @param {Chunk} chunk the chunk
3906
+ * @returns {WasmLoading} the loader it is served by
3907
+ */
3908
+ _chunkWasmLoading(chunk) {
3909
+ const entryOptions = chunk.getEntryOptions();
3910
+ return entryOptions && entryOptions.wasmLoading !== undefined
3911
+ ? entryOptions.wasmLoading
3912
+ : this.outputOptions.wasmLoading;
1796
3913
  }
1797
3914
 
1798
3915
  /**
@@ -1802,16 +3919,24 @@ class RuntimeTemplate {
1802
3919
  * @param {ChunkGraph} options.chunkGraph the chunk graph
1803
3920
  * @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
1804
3921
  * @param {string=} options.request request string used originally
3922
+ * @param {Module=} options.originModule the module the factory is emitted into
1805
3923
  * @returns {string} expression
1806
3924
  */
1807
- asyncModuleFactory({ block, chunkGraph, runtimeRequirements, request }) {
3925
+ asyncModuleFactory({
3926
+ block,
3927
+ chunkGraph,
3928
+ runtimeRequirements,
3929
+ request,
3930
+ originModule
3931
+ }) {
1808
3932
  const dep = block.dependencies[0];
1809
3933
  const module = chunkGraph.moduleGraph.getModule(dep);
1810
3934
  const ensureChunk = this.blockPromise({
1811
3935
  block,
1812
3936
  message: "",
1813
3937
  chunkGraph,
1814
- runtimeRequirements
3938
+ runtimeRequirements,
3939
+ originModule
1815
3940
  });
1816
3941
  const factory = this.returningFunction(
1817
3942
  this.moduleRaw({
@@ -1862,6 +3987,326 @@ class RuntimeTemplate {
1862
3987
  runtimeRequirements.add(RuntimeGlobals.exports);
1863
3988
  return `${RuntimeGlobals.makeNamespaceObject}(${exportsArgument});\n`;
1864
3989
  }
3990
+
3991
+ /**
3992
+ * Reserves a name only the deferred pass can spell, as a stand-in that looks like a
3993
+ * relative specifier so the code around it needs no special case. It carries what it
3994
+ * resolves to rather than an index into per-build state — a module restored from the
3995
+ * persistent cache is never generated again.
3996
+ * @param {SpecifierPart[]} parts what the stand-in resolves to, in order
3997
+ * @returns {string} the stand-in to emit
3998
+ */
3999
+ _reserveAnalyzableSpecifier(parts) {
4000
+ return `./@@webpackAnalyzableChunk:${Buffer.from(JSON.stringify(parts))
4001
+ .toString("base64")
4002
+ .replace(/\+/g, "-")
4003
+ .replace(/\//g, "_")
4004
+ .replace(/[=]/g, "")}@@`;
4005
+ }
4006
+
4007
+ /**
4008
+ * Whether text still carries a compilation-hash stand-in, so nothing may be resolved
4009
+ * against it here — the fill would land inside an already-resolved result.
4010
+ * @param {string} value text that may carry one
4011
+ * @returns {boolean} true when one is present
4012
+ */
4013
+ _hasReservedFullHash(value) {
4014
+ return value.includes(FULL_HASH_TOKEN_PREFIX);
4015
+ }
4016
+
4017
+ /**
4018
+ * `getPath` data that leaves every compilation-hash placeholder as a stand-in while
4019
+ * the rest of the name resolves.
4020
+ * @returns {typeof DEFERRED_FULL_HASH_PATH_DATA} the path data
4021
+ */
4022
+ _deferredFullHashPathData() {
4023
+ return DEFERRED_FULL_HASH_PATH_DATA;
4024
+ }
4025
+
4026
+ /**
4027
+ * Fills in the names reserved during code generation, once the hashes they are built
4028
+ * from exist: a chunk's own filename, and the compilation hash inside any other
4029
+ * emitted asset's. Replaces in place so the asset keeps its mappings, and runs before
4030
+ * anything reads it — `RealContentHashPlugin` still repairs each rewritten chunk's own
4031
+ * name later. Registered wherever `output.module` is read, since nothing reserves a
4032
+ * stand-in without it — a reservation cannot arrange this itself, as a module restored
4033
+ * from the cache carries one without being generated again.
4034
+ * @param {Compiler} compiler the compiler
4035
+ * @returns {void}
4036
+ */
4037
+ static fillReservedNames(compiler) {
4038
+ compiler.hooks.compilation.tap(PASS_NAME, (compilation) => {
4039
+ const cache = compilation.getCache(PASS_NAME);
4040
+ // Code generation is over, so what carries the compilation hash is settled and
4041
+ // each such chunk can be moved into the round that follows that hash.
4042
+ compilation.hooks.beforeHash.tap(PASS_NAME, () => {
4043
+ compilation.runtimeTemplate._markChunksSettlingLate();
4044
+ });
4045
+ // Reaches both `chunk.hash` and `chunk.contentHash.javascript`, the two a
4046
+ // filled-in name can leave behind.
4047
+ JavascriptModulesPlugin.getCompilationHooks(compilation).chunkHash.tap(
4048
+ PASS_NAME,
4049
+ (chunk, hash) => {
4050
+ compilation.runtimeTemplate._foldAnalyzableNames(chunk, hash);
4051
+ }
4052
+ );
4053
+ // Nothing past hashing reads what the fold cached, and it holds a name per
4054
+ // edge between chunks, so it is dropped rather than kept until seal.
4055
+ compilation.hooks.afterHash.tap(PASS_NAME, () => {
4056
+ compilation.runtimeTemplate._releaseAnalyzableNameCaches();
4057
+ });
4058
+ compilation.hooks.processAssets.tapPromise(
4059
+ {
4060
+ 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.
4066
+ stage: getCompilation().PROCESS_ASSETS_STAGE_DERIVED
4067
+ },
4068
+ async () => {
4069
+ const { outputOptions } = compilation;
4070
+ const fullHash = compilation.hash;
4071
+ /** @type {Map<string, Chunk> | undefined} */
4072
+ let chunksById;
4073
+ /** @type {Map<string, Chunk> | undefined} */
4074
+ let chunkByAsset;
4075
+ /** @type {string | undefined} */
4076
+ let publicPathText;
4077
+ // One value for the whole pass, however many stand-ins read it.
4078
+ const resolvedPublicPath = () => {
4079
+ if (publicPathText === undefined) {
4080
+ publicPathText = compilation.getPath(
4081
+ outputOptions.publicPath || "",
4082
+ {}
4083
+ );
4084
+ }
4085
+ return publicPathText;
4086
+ };
4087
+ /**
4088
+ * @param {string} name an emitted asset's name
4089
+ * @returns {Chunk | undefined} the chunk it was emitted for
4090
+ */
4091
+ const chunkOf = (name) => {
4092
+ if (chunkByAsset === undefined) {
4093
+ chunkByAsset = new Map();
4094
+ for (const chunk of compilation.chunks) {
4095
+ for (const file of chunk.files) chunkByAsset.set(file, chunk);
4096
+ }
4097
+ }
4098
+ return chunkByAsset.get(name);
4099
+ };
4100
+ /**
4101
+ * @param {string} value text that may carry compilation-hash stand-ins
4102
+ * @returns {string} the text with each of them filled in
4103
+ */
4104
+ const fillFullHash = (value) => {
4105
+ if (fullHash === undefined) return value;
4106
+ FULL_HASH_TOKEN_REGEXP.lastIndex = 0;
4107
+ return value.replace(FULL_HASH_TOKEN_REGEXP, (_match, length) =>
4108
+ length === undefined
4109
+ ? fullHash
4110
+ : fullHash.slice(0, Number(length))
4111
+ );
4112
+ };
4113
+ /**
4114
+ * @param {string} payload the encoded half of a stand-in
4115
+ * @param {string} assetName name of the asset the stand-in sits in
4116
+ * @returns {string | null} the specifier, or `null` if unresolvable
4117
+ */
4118
+ const resolve = (payload, assetName) => {
4119
+ const parts = RuntimeTemplate._readAnalyzableSpecifier(payload);
4120
+ if (parts === null) return null;
4121
+ /** @type {string | undefined} */
4122
+ let base;
4123
+ let specifier = "";
4124
+ for (const [kind, value] of parts) {
4125
+ if (kind === "base") {
4126
+ base = /** @type {string} */ (value);
4127
+ } else if (kind === "literal") {
4128
+ specifier += value;
4129
+ } else if (kind === "undo") {
4130
+ specifier += getUndoPath(
4131
+ assetName,
4132
+ /** @type {string} */ (outputOptions.path),
4133
+ true
4134
+ );
4135
+ } else if (kind === "template") {
4136
+ specifier += compilation.getPath(
4137
+ /** @type {string} */ (value),
4138
+ {}
4139
+ );
4140
+ } else if (kind === "publicPath") {
4141
+ specifier += resolvedPublicPath();
4142
+ } else if (kind === "unserved") {
4143
+ const holder = chunkOf(assetName);
4144
+ if (holder === undefined) return null;
4145
+ // Only an asset the host fetched needs the public path put in
4146
+ // front. One the loader fetched already sits under it, and the
4147
+ // `../` ahead of this walked back to exactly there.
4148
+ if (
4149
+ compilation.runtimeTemplate._chunkPlacement(holder).loaded ===
4150
+ false
4151
+ ) {
4152
+ const path = resolvedPublicPath();
4153
+ // The `../` already reached the root this is read from.
4154
+ specifier += path.startsWith("./") ? path.slice(2) : path;
4155
+ }
4156
+ } else {
4157
+ const naming = CHUNK_ASSET_NAMING_BY_STAND_IN.get(kind);
4158
+ // Nothing reserves a kind this pass cannot spell, so one arriving
4159
+ // here was written by something else and names no asset of ours.
4160
+ if (naming === undefined) return null;
4161
+ if (chunksById === undefined) {
4162
+ chunksById = new Map();
4163
+ for (const chunk of compilation.chunks) {
4164
+ if (chunk.id !== null) {
4165
+ chunksById.set(String(chunk.id), chunk);
4166
+ }
4167
+ }
4168
+ }
4169
+ const chunk = chunksById.get(String(value));
4170
+ if (chunk === undefined) return null;
4171
+ specifier += compilation.getPath(
4172
+ naming.template(chunk, outputOptions),
4173
+ // Matches what names the asset, or a placeholder resolved here would
4174
+ // not be the one on disk.
4175
+ {
4176
+ chunk,
4177
+ runtime: chunk.runtime,
4178
+ contentHashType: naming.contentHashType
4179
+ }
4180
+ );
4181
+ }
4182
+ }
4183
+ if (base !== undefined) {
4184
+ // An entry base replaces the output root, so the rest is read against it
4185
+ // here exactly as the runtime would have read it against `.b`.
4186
+ try {
4187
+ return new URL(fillFullHash(specifier), base).href;
4188
+ } catch (_error) {
4189
+ return null;
4190
+ }
4191
+ }
4192
+ // A bare specifier is a package name, so make it explicitly relative the way
4193
+ // the chunk loader does. A literal part may still carry a stand-in of its own,
4194
+ // so finish those here rather than scanning again.
4195
+ return fillFullHash(
4196
+ /^(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(specifier)
4197
+ ? specifier
4198
+ : `./${specifier}`
4199
+ );
4200
+ };
4201
+ /** @type {{ name: string, source: Source, replacements: Replacement[] }[]} */
4202
+ const tasks = [];
4203
+
4204
+ for (const name of Object.keys(compilation.assets)) {
4205
+ const source = compilation.assets[name];
4206
+ const content = source.source();
4207
+ if (typeof content !== "string") continue;
4208
+ ANALYZABLE_TOKEN_REGEXP.lastIndex = 0;
4209
+ FULL_HASH_TOKEN_REGEXP.lastIndex = 0;
4210
+ const hasChunkToken = ANALYZABLE_TOKEN_REGEXP.test(content);
4211
+ const hasFullHashToken =
4212
+ fullHash !== undefined && FULL_HASH_TOKEN_REGEXP.test(content);
4213
+ if (!hasChunkToken && !hasFullHashToken) continue;
4214
+ /** @type {Replacement[]} */
4215
+ const replacements = [];
4216
+ /**
4217
+ * @param {RegExp} pattern what to look for
4218
+ * @param {(match: string, group: string) => string | null} fill what to put there
4219
+ * @returns {void}
4220
+ */
4221
+ const collect = (pattern, fill) => {
4222
+ // Its own instance: `fill` may run the shared one over what it
4223
+ // returns, and a `replace` there would rewind this scan.
4224
+ const regexp = new RegExp(pattern.source, pattern.flags);
4225
+ /** @type {RegExpExecArray | null} */
4226
+ let match;
4227
+ while ((match = regexp.exec(content)) !== null) {
4228
+ const value = fill(match[0], match[1]);
4229
+ if (value === null) continue;
4230
+ replacements.push([
4231
+ match.index,
4232
+ match.index + match[0].length - 1,
4233
+ value
4234
+ ]);
4235
+ }
4236
+ };
4237
+ if (hasChunkToken) {
4238
+ collect(ANALYZABLE_TOKEN_REGEXP, (_match, payload) =>
4239
+ resolve(payload, name)
4240
+ );
4241
+ }
4242
+ if (hasFullHashToken) {
4243
+ collect(FULL_HASH_TOKEN_REGEXP, (match) => fillFullHash(match));
4244
+ }
4245
+ if (replacements.length === 0) continue;
4246
+
4247
+ tasks.push({ name, source, replacements });
4248
+ }
4249
+ if (tasks.length === 0) return;
4250
+
4251
+ await Promise.all(
4252
+ tasks.map(async ({ name, source, replacements }) => {
4253
+ const replaced = await cache.providePromise(
4254
+ name,
4255
+ cache.mergeEtags(
4256
+ cache.getLazyHashedEtag(source),
4257
+ JSON.stringify(replacements)
4258
+ ),
4259
+ () => {
4260
+ const replacedSource = new ReplaceSource(source);
4261
+ for (const [start, end, value] of replacements) {
4262
+ replacedSource.replace(start, end, value);
4263
+ }
4264
+ return new CachedSource(replacedSource);
4265
+ }
4266
+ );
4267
+ compilation.updateAsset(name, replaced);
4268
+ })
4269
+ );
4270
+ }
4271
+ );
4272
+ });
4273
+ }
4274
+
4275
+ /**
4276
+ * Reads back what `_reserveAnalyzableSpecifier` wrote. Source of our own can spell the
4277
+ * token too, so nothing about a payload is given and every shape it does not produce
4278
+ * is refused rather than reached for.
4279
+ * @param {string} payload the encoded half of a stand-in
4280
+ * @returns {SpecifierPart[] | null} what it resolves to, or `null` if unreadable
4281
+ */
4282
+ static _readAnalyzableSpecifier(payload) {
4283
+ /** @type {EXPECTED_ANY} */
4284
+ let decoded;
4285
+ try {
4286
+ decoded = JSON.parse(
4287
+ Buffer.from(
4288
+ payload.replace(/-/g, "+").replace(/_/g, "/"),
4289
+ "base64"
4290
+ ).toString()
4291
+ );
4292
+ } catch (_error) {
4293
+ return null;
4294
+ }
4295
+ if (!Array.isArray(decoded)) return null;
4296
+ for (const part of decoded) {
4297
+ if (!Array.isArray(part) || part.length !== 2) return null;
4298
+ if (!SPECIFIER_PART_KINDS.has(part[0])) return null;
4299
+ // Only a chunk id may be a number; the rest are read as text.
4300
+ if (
4301
+ typeof part[1] !== "string" &&
4302
+ (!CHUNK_SPECIFIER_PART_KINDS.has(part[0]) ||
4303
+ typeof part[1] !== "number")
4304
+ ) {
4305
+ return null;
4306
+ }
4307
+ }
4308
+ return decoded;
4309
+ }
1865
4310
  }
1866
4311
 
1867
4312
  module.exports = RuntimeTemplate;