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