@depup/webpack 5.109.2-depup.0 → 5.110.1-depup.0

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