@depup/webpack 5.110.1-depup.0 → 5.111.1-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -8
- package/changes.json +7 -11
- package/lib/APIPlugin.js +26 -11
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/Cache.js +8 -3
- package/lib/CacheFacade.js +1 -1
- package/lib/ChunkGraph.js +20 -18
- package/lib/CircularModulesPlugin.js +157 -55
- package/lib/CleanPlugin.js +2 -2
- package/lib/CompatibilityPlugin.js +3 -4
- package/lib/Compilation.js +337 -338
- package/lib/Compiler.js +213 -51
- package/lib/ConcatenationScope.js +25 -35
- package/lib/ConstPlugin.js +16 -132
- package/lib/CopyPlugin.js +1054 -0
- package/lib/DefinePlugin.js +24 -8
- package/lib/DependencyTemplate.js +2 -1
- package/lib/DotenvPlugin.js +64 -40
- package/lib/ErrorHelpers.js +113 -0
- package/lib/ExportsInfo.js +30 -16
- package/lib/ExternalModule.js +47 -22
- package/lib/FileSystemInfo.js +17 -14
- package/lib/FlagDependencyExportsPlugin.js +53 -34
- package/lib/FlagDependencyUsagePlugin.js +17 -15
- package/lib/Generator.js +24 -2
- package/lib/HotModuleReplacementPlugin.js +55 -7
- package/lib/IgnorePlugin.js +1 -1
- package/lib/JavascriptMetaInfoPlugin.js +5 -3
- package/lib/LoaderOptionsPlugin.js +1 -1
- package/lib/MainTemplate.js +5 -1
- package/lib/Module.js +19 -10
- package/lib/ModuleGraph.js +6 -9
- package/lib/MultiCompiler.js +7 -17
- package/lib/MultiWatching.js +1 -1
- package/lib/NormalModule.js +148 -70
- package/lib/NormalModuleFactory.js +1 -1
- package/lib/RuntimeGlobals.js +21 -7
- package/lib/RuntimeModule.js +28 -12
- package/lib/RuntimePlugin.js +33 -3
- package/lib/RuntimeTemplate.js +1147 -847
- package/lib/SourceMapDevToolPlugin.js +54 -104
- package/lib/TemplatedPathPlugin.js +16 -59
- package/lib/Watching.js +9 -0
- package/lib/WebpackOptionsApply.js +84 -91
- package/lib/asset/AssetBytesGenerator.js +7 -1
- package/lib/asset/AssetGenerator.js +50 -24
- package/lib/asset/AssetModule.js +3 -0
- package/lib/asset/AssetSourceGenerator.js +7 -1
- package/lib/asset/WebManifestParser.js +7 -5
- package/lib/async-modules/AsyncModuleHelpers.js +10 -4
- package/lib/buildChunkGraph.js +11 -15
- package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/MemoryCachePlugin.js +4 -4
- package/lib/cache/MemoryWithGcCachePlugin.js +7 -8
- package/lib/cache/PackFileCacheStrategy.js +17 -19
- package/lib/cache/getLazyHashedEtag.js +3 -5
- package/lib/config/browserslistTargetHandler.js +17 -4
- package/lib/config/defaults.js +162 -142
- package/lib/config/getClaimedAssetTypes.js +10 -11
- package/lib/config/normalization.js +100 -20
- package/lib/config/target.js +13 -4
- package/lib/container/ContainerReferencePlugin.js +6 -0
- package/lib/container/RemoteRuntimeModule.js +9 -0
- package/lib/container/declaredRemotes.js +39 -0
- package/lib/{ContextExclusionPlugin.js → context/ContextExclusionPlugin.js} +1 -1
- package/lib/{ContextModule.js → context/ContextModule.js} +54 -115
- package/lib/{ContextModuleFactory.js → context/ContextModuleFactory.js} +19 -21
- package/lib/{ContextReplacementPlugin.js → context/ContextReplacementPlugin.js} +4 -4
- package/lib/css/CssGenerator.js +27 -11
- package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
- package/lib/css/CssLoadingRuntimeModule.js +92 -15
- package/lib/css/CssModule.js +1 -1
- package/lib/css/CssModulesPlugin.js +3 -10
- package/lib/css/CssParser.js +162 -31
- package/lib/css/CssServerStylesRuntimeModule.js +9 -0
- package/lib/css/cssMinify.js +43 -32
- package/lib/css/data.js +3526 -871
- package/lib/css/syntax.js +6455 -1237
- package/lib/debug/ProfilingPlugin.js +7 -4
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
- package/lib/dependencies/AMDRuntimeModules.js +18 -0
- package/lib/dependencies/CommonJsExportRequireDependency.js +13 -12
- package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
- package/lib/dependencies/CommonJsImportsParserPlugin.js +5 -5
- package/lib/dependencies/CommonJsPlugin.js +19 -3
- package/lib/dependencies/CommonJsRequireDependency.js +32 -9
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +2 -4
- package/lib/dependencies/ContextDependency.js +1 -1
- package/lib/dependencies/ContextDependencyHelpers.js +3 -9
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +20 -7
- package/lib/dependencies/ContextElementDependency.js +1 -1
- package/lib/dependencies/CssIcssExportDependency.js +13 -9
- package/lib/dependencies/CssIcssImportDependency.js +3 -6
- package/lib/dependencies/CssUrlDependency.js +3 -5
- package/lib/dependencies/HarmonyCompatibilityDependency.js +67 -22
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +3 -4
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +10 -4
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +12 -7
- package/lib/dependencies/HarmonyExportExpressionDependency.js +47 -33
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +217 -34
- package/lib/dependencies/HarmonyExportInitFragment.js +110 -23
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +25 -58
- package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
- package/lib/dependencies/HarmonyImportDependency.js +99 -41
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +198 -25
- package/lib/dependencies/HarmonyImportSideEffectDependency.js +117 -4
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +40 -3
- package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
- package/lib/dependencies/HtmlEntryDependency.js +136 -104
- package/lib/dependencies/HtmlInlineScriptDependency.js +3 -4
- package/lib/dependencies/HtmlInlineStyleDependency.js +3 -4
- package/lib/dependencies/ImportContextDependency.js +43 -3
- package/lib/dependencies/ImportDependency.js +8 -29
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/ImportMetaGlobHelpers.js +1 -1
- package/lib/dependencies/ImportMetaMainDependency.js +104 -0
- package/lib/dependencies/ImportMetaPlugin.js +67 -25
- package/lib/dependencies/ImportParserPlugin.js +25 -15
- package/lib/dependencies/LoaderPlugin.js +26 -1
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/RequireHeaderDependency.js +20 -21
- package/lib/dependencies/SystemRuntimeModule.js +9 -0
- package/lib/dependencies/URLContextDependency.js +1 -1
- package/lib/dependencies/URLDependency.js +6 -5
- package/lib/dependencies/WorkerAndWorkletPlugin.js +16 -21
- package/lib/dependencies/WorkerDependency.js +12 -18
- package/lib/dependencies/WorkletDependency.js +12 -20
- package/lib/dependencies/importOptionsCheck.js +47 -0
- package/lib/dll/DelegatedModule.js +18 -1
- package/lib/dll/DllReferencePlugin.js +11 -8
- package/lib/dll/LibManifestPlugin.js +1 -1
- package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
- package/lib/errors/DotenvFileError.js +29 -0
- package/lib/errors/DuplicateModulesWarning.js +12 -7
- package/lib/errors/EmptyCopyPatternWarning.js +26 -0
- package/lib/errors/ExternalStarReexportError.js +44 -0
- package/lib/errors/HookWebpackError.js +3 -2
- package/lib/errors/ImportedBindingAssignmentError.js +30 -0
- package/lib/errors/MissingSourceMapsWarning.js +36 -0
- package/lib/errors/ModuleParseError.js +2 -1
- package/lib/errors/UnusedAssetsWarning.js +36 -0
- package/lib/errors/UnusedFederationWarning.js +35 -0
- package/lib/errors/UnusedModulesWarning.js +38 -0
- package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
- package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
- package/lib/esm/ModuleChunkLoadingPlugin.js +21 -5
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +91 -53
- package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
- package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
- package/lib/hmr/LazyCompilationPlugin.js +3 -5
- package/lib/html/HtmlGenerator.js +72 -87
- package/lib/html/HtmlModulesPlugin.js +479 -215
- package/lib/html/HtmlParser.js +110 -147
- package/lib/html/builtinEmbeddedRenderer.js +107 -0
- package/lib/html/data.js +142 -7
- package/lib/html/htmlMinify.js +92 -122
- package/lib/html/syntax.js +2031 -1556
- package/lib/ids/HashedModuleIdsPlugin.js +2 -1
- package/lib/index.js +49 -3
- package/lib/javascript/ChunkFormatHelpers.js +4 -3
- package/lib/javascript/JavascriptGenerator.js +8 -1
- package/lib/javascript/JavascriptModule.js +1 -0
- package/lib/javascript/JavascriptModulesPlugin.js +76 -80
- package/lib/javascript/JavascriptParser.js +1970 -900
- package/lib/javascript/StartupHelpers.js +27 -3
- package/lib/javascript/data.js +172 -0
- package/lib/javascript/grammar.js +5546 -0
- package/lib/javascript/parser.js +1500 -0
- package/lib/javascript/regexp.js +1762 -0
- package/lib/javascript/regexpData.js +51 -0
- package/lib/javascript/syntax.js +9061 -5262
- package/lib/json/JsonGenerator.js +7 -1
- package/lib/library/ModuleLibraryPlugin.js +171 -132
- package/lib/loaders/LoaderRunner.js +170 -14
- package/lib/node/NodeWatchFileSystem.js +3 -9
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +8 -15
- package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
- package/lib/optimize/AggressiveMergingPlugin.js +3 -5
- package/lib/optimize/ConcatenatedModule.js +222 -125
- package/lib/optimize/ConstExportsPlugin.js +50 -34
- package/lib/optimize/FlagIncludedChunksPlugin.js +3 -11
- package/lib/optimize/InlineExports.js +20 -2
- package/lib/optimize/InnerGraphPlugin.js +7 -13
- package/lib/optimize/LimitChunkCountPlugin.js +5 -8
- package/lib/optimize/MangleExportsPlugin.js +13 -4
- package/lib/optimize/ModuleConcatenationPlugin.js +27 -5
- package/lib/optimize/RealContentHashPlugin.js +179 -44
- package/lib/optimize/SideEffectsFlagPlugin.js +24 -28
- package/lib/optimize/SplitChunksPlugin.js +2 -4
- package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
- package/lib/performance/BroadContextsPlugin.js +1 -1
- package/lib/performance/CacheEffectivenessPlugin.js +7 -7
- package/lib/performance/DuplicateModulesPlugin.js +57 -13
- package/lib/performance/EvalUsagePlugin.js +5 -2
- package/lib/performance/MissingSourceMapsPlugin.js +115 -0
- package/lib/performance/PureAnnotationsPlugin.js +6 -3
- package/lib/performance/SizeLimitsPlugin.js +2 -4
- package/lib/performance/TopLevelThisPlugin.js +5 -4
- package/lib/performance/UnusedAssetsPlugin.js +109 -0
- package/lib/performance/UnusedFederationPlugin.js +147 -0
- package/lib/performance/UnusedModulesPlugin.js +141 -0
- package/lib/performance/UnusedReexportsPlugin.js +1 -55
- package/lib/performance/isOnlyReexported.js +65 -0
- package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +8 -8
- package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
- package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
- package/lib/prefetch/ResourceHintPlugin.js +29 -35
- package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +16 -10
- package/lib/rules/RuleSetCompiler.js +211 -4
- package/lib/runtime/AsyncModuleRuntimeModule.js +103 -67
- package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
- package/lib/runtime/BaseUriRuntimeModule.js +9 -0
- package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
- package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +12 -4
- package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
- package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
- package/lib/runtime/GlobalRuntimeModule.js +11 -4
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
- package/lib/runtime/HelperRuntimeModule.js +10 -0
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +313 -222
- package/lib/runtime/NonceRuntimeModule.js +9 -0
- package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
- package/lib/runtime/PublicPathRuntimeModule.js +9 -0
- package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
- package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
- package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
- package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
- package/lib/runtime/SystemContextRuntimeModule.js +9 -0
- package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
- package/lib/schemes/DataUriPlugin.js +3 -6
- package/lib/schemes/HttpUriPlugin.js +22 -5
- package/lib/schemes/VirtualUrlPlugin.js +1 -1
- package/lib/serialization/BinaryMiddleware.js +9 -9
- package/lib/serialization/FileMiddleware.js +31 -18
- package/lib/serialization/ObjectMiddleware.js +168 -139
- package/lib/sharing/ConsumeSharedPlugin.js +12 -0
- package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
- package/lib/sharing/ShareRuntimeModule.js +9 -0
- package/lib/sharing/declaredShared.js +47 -0
- package/lib/stats/DefaultStatsFactoryPlugin.js +6 -5
- package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
- package/lib/typescript/TypeScriptPlugin.js +10 -13
- package/lib/url/URLParserPlugin.js +6 -8
- package/lib/util/ArrayQueue.js +3 -3
- package/lib/util/LocConverter.js +4 -7
- package/lib/util/SourceProcessor.js +115 -99
- package/lib/util/URLAbsoluteSpecifier.js +3 -1
- package/lib/util/async.js +292 -0
- package/lib/util/buildDiagnostics.js +69 -0
- package/lib/util/chainedImports.js +3 -4
- package/lib/util/concatenate.js +4 -4
- package/lib/util/conventions.js +5 -1
- package/lib/util/createHooksRegistry.js +1 -2
- package/lib/util/createMappings.js +25 -3
- package/lib/util/dataURL.js +2 -3
- package/lib/util/deterministicGrouping.js +8 -13
- package/lib/util/findGraphRoots.js +6 -13
- package/lib/util/fs.js +27 -1
- package/lib/util/globUtils.js +1 -1
- package/lib/util/handlerKeys.js +40 -0
- package/lib/util/hash/wasm-hash.js +3 -4
- package/lib/util/identifier.js +20 -0
- package/lib/util/internalSerializables.js +7 -1
- package/lib/util/registerExternalSerializer.js +6 -45
- package/lib/util/removeBOM.js +82 -1
- package/lib/util/semver.js +5 -3
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +14 -3
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +14 -3
- package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -1
- package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -1
- package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +7 -12
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +12 -4
- package/lib/wasm-sync/WebAssemblyGenerator.js +6 -1
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -1
- package/lib/wasm-sync/WebAssemblyUtils.js +2 -4
- package/lib/web/FetchCompileAsyncWasmPlugin.js +10 -6
- package/lib/web/FetchCompileWasmPlugin.js +4 -2
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
- package/package.json +55 -46
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +388 -76
- package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
- package/schemas/plugins/ManifestPlugin.check.js +1 -1
- package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
- package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
- package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
- package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
- package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
- package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
- package/types.d.ts +1795 -608
- package/lib/dependencies/ExportBindingInitFragment.js +0 -191
- package/lib/errors/EntrypointOverlapWarning.js +0 -45
- package/lib/performance/EntrypointOverlapPlugin.js +0 -122
package/lib/RuntimeTemplate.js
CHANGED
|
@@ -9,14 +9,7 @@ const { CachedSource, ReplaceSource } = require("webpack-sources");
|
|
|
9
9
|
const APIPlugin = require("./APIPlugin");
|
|
10
10
|
|
|
11
11
|
const InitFragment = require("./InitFragment");
|
|
12
|
-
const {
|
|
13
|
-
ASSET_TYPE,
|
|
14
|
-
ASSET_URL_TYPE,
|
|
15
|
-
CSS_TYPE,
|
|
16
|
-
HTML_TYPE,
|
|
17
|
-
JAVASCRIPT_TYPE,
|
|
18
|
-
RUNTIME_TYPE
|
|
19
|
-
} = require("./ModuleSourceTypeConstants");
|
|
12
|
+
const { CSS_TYPE, JAVASCRIPT_TYPE } = require("./ModuleSourceTypeConstants");
|
|
20
13
|
const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("./ModuleTypeConstants");
|
|
21
14
|
const RuntimeGlobals = require("./RuntimeGlobals");
|
|
22
15
|
const Template = require("./Template");
|
|
@@ -31,6 +24,7 @@ const { InlinedUsedName } = require("./optimize/InlineExports");
|
|
|
31
24
|
const {
|
|
32
25
|
getDeferredCycleModuleIds,
|
|
33
26
|
getDeferredCycleModules,
|
|
27
|
+
getKnownExportNames,
|
|
34
28
|
getMakeDeferredNamespaceModeFromExportsType,
|
|
35
29
|
getOptimizedDeferredModule
|
|
36
30
|
} = require("./runtime/MakeDeferredNamespaceObjectRuntime");
|
|
@@ -42,7 +36,11 @@ const { equals } = require("./util/ArrayHelpers");
|
|
|
42
36
|
const { getScheme } = require("./util/URLAbsoluteSpecifier");
|
|
43
37
|
const { compareIds } = require("./util/comparators");
|
|
44
38
|
const compileBooleanMatcher = require("./util/compileBooleanMatcher");
|
|
45
|
-
const {
|
|
39
|
+
const {
|
|
40
|
+
RESOLVABLE_SPECIFIER_REGEXP,
|
|
41
|
+
getUndoPath,
|
|
42
|
+
toJsStringLiteral
|
|
43
|
+
} = require("./util/identifier");
|
|
46
44
|
const memoize = require("./util/memoize");
|
|
47
45
|
const { propertyAccess, propertyName } = require("./util/property");
|
|
48
46
|
const {
|
|
@@ -55,6 +53,7 @@ const {
|
|
|
55
53
|
const getCssModulesPlugin = memoize(() => require("./css/CssModulesPlugin"));
|
|
56
54
|
// `Compilation` requires this module, so its stage constants are read lazily.
|
|
57
55
|
const getCompilation = memoize(() => require("./Compilation"));
|
|
56
|
+
const getExternalModule = memoize(() => require("./ExternalModule"));
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* @typedef {object} ChunkAssetNaming
|
|
@@ -91,6 +90,20 @@ const getTemplatedPathPlugin = memoize(() => require("./TemplatedPathPlugin"));
|
|
|
91
90
|
const getConcatenatedModule = memoize(() =>
|
|
92
91
|
require("./optimize/ConcatenatedModule")
|
|
93
92
|
);
|
|
93
|
+
const getNormalModule = memoize(() => require("./NormalModule"));
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Whether a hot update can re-run the module a reference is emitted into: the HMR
|
|
97
|
+
* plugin marks every normal module, and a concatenated one is read through its root.
|
|
98
|
+
* @param {Module | undefined} module the module a reference is emitted into
|
|
99
|
+
* @returns {boolean} true under HMR
|
|
100
|
+
*/
|
|
101
|
+
const isHotModule = (module) => {
|
|
102
|
+
if (module === undefined) return false;
|
|
103
|
+
const normal =
|
|
104
|
+
module instanceof getConcatenatedModule() ? module.rootModule : module;
|
|
105
|
+
return normal instanceof getNormalModule() && normal.hot;
|
|
106
|
+
};
|
|
94
107
|
|
|
95
108
|
// Any `[hash]`/`[fullhash]`/`[chunkhash]`/`[contenthash]` token, incl. a `:<length>`
|
|
96
109
|
// or `:<digest>[:<length>]` suffix (e.g. `[contenthash:base64:8]`). Its value is only
|
|
@@ -103,6 +116,9 @@ const HASH_PROBE = "0123456789abcdef0123";
|
|
|
103
116
|
const HASH_PROBE_ALTERNATE = "3210fedcba9876543210";
|
|
104
117
|
const HASH_IN_FILENAME_GLOBAL = /\[(?:full|chunk|content)?hash(?::[^\]]+)?\]/g;
|
|
105
118
|
|
|
119
|
+
// What a recorded reason is prefixed with in `stats.optimizationBailout`.
|
|
120
|
+
const ANALYZABLE_BAILOUT_PREFIX = "Analyzable ESM bailout: ";
|
|
121
|
+
|
|
106
122
|
/**
|
|
107
123
|
* @param {SpecifierPart} part one piece of a reserved name
|
|
108
124
|
* @returns {boolean} true when it is text the deferred pass adds nothing to
|
|
@@ -155,21 +171,6 @@ const rootedParts = (parts) =>
|
|
|
155
171
|
]
|
|
156
172
|
: parts;
|
|
157
173
|
|
|
158
|
-
// Types that ride the chunk itself or render their own asset, so no `.f` handler
|
|
159
|
-
// fetches them; every other type may install one, so the map has to exist for it.
|
|
160
|
-
/** @type {Set<string>} */
|
|
161
|
-
const TYPES_WITHOUT_CHUNK_HANDLER = new Set([
|
|
162
|
-
JAVASCRIPT_TYPE,
|
|
163
|
-
RUNTIME_TYPE,
|
|
164
|
-
ASSET_TYPE,
|
|
165
|
-
ASSET_URL_TYPE,
|
|
166
|
-
HTML_TYPE
|
|
167
|
-
]);
|
|
168
|
-
|
|
169
|
-
// Why a name only the deferred pass could settle was not deferred.
|
|
170
|
-
const DEFER_BAILOUT =
|
|
171
|
-
"a hashed name needs optimization.realContentHash, or no emitted javascript named by its content";
|
|
172
|
-
|
|
173
174
|
/**
|
|
174
175
|
* Where a literal is read from — the `../` path back to the output root, and whether
|
|
175
176
|
* the chunk loader fetched the chunk it sits in through `output.publicPath`.
|
|
@@ -178,6 +179,13 @@ const DEFER_BAILOUT =
|
|
|
178
179
|
* @property {boolean | null} loaded whether the chunk loader fetched the chunk
|
|
179
180
|
*/
|
|
180
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @typedef {object} WasmGroups
|
|
184
|
+
* @property {(key: string) => string} groupOf the group a runtime key answers with
|
|
185
|
+
* @property {Set<string>} fetching groups an entry of which reads binaries with `fetch`
|
|
186
|
+
* @property {Map<string, boolean>} onlyFetching groups every entry of which fetches
|
|
187
|
+
*/
|
|
188
|
+
|
|
181
189
|
// A reference in no chunk at all: nothing is known about where it is read from.
|
|
182
190
|
/** @type {Placement} */
|
|
183
191
|
const NO_PLACEMENT = { undo: null, loaded: null };
|
|
@@ -202,7 +210,12 @@ const RUNTIME_HASH_ROUND = 2;
|
|
|
202
210
|
|
|
203
211
|
// Why a public path needing a base could not be spelled from the chunk holding it.
|
|
204
212
|
const SERVED_BAILOUT =
|
|
205
|
-
|
|
213
|
+
'this module is in a chunk webpack loads through output.publicPath and in one it does not, so no one path back to the output root fits both (a root-absolute or absolute output.publicPath, or "auto", is read the same from both)';
|
|
214
|
+
|
|
215
|
+
// Why a runtime's url map kept the runtime form under HMR: an update re-ships the
|
|
216
|
+
// runtime module only when its own code changes.
|
|
217
|
+
const HOT_NAME_BAILOUT =
|
|
218
|
+
"a hot update can move this name without changing the runtime module that spells it, so the update would not carry the new one";
|
|
206
219
|
|
|
207
220
|
/**
|
|
208
221
|
* @import {
|
|
@@ -223,8 +236,9 @@ const SERVED_BAILOUT =
|
|
|
223
236
|
* One piece of a name only the deferred pass can spell: text as it stands, the `../`
|
|
224
237
|
* path from the asset it sits in to the output root, a template or `output.publicPath`
|
|
225
238
|
* resolved once the hashes exist, one of the assets the chunk with this id emits, or
|
|
226
|
-
* the base everything else is resolved against once it is spelled.
|
|
227
|
-
*
|
|
239
|
+
* the base everything else is resolved against once it is spelled. A `repair` part
|
|
240
|
+
* spells nothing: it marks a name the repair pass has to bring back in line.
|
|
241
|
+
* @typedef {"literal" | "undo" | "template" | "publicPath" | "unserved" | "chunk" | "cssChunk" | "base" | "repair"} SpecifierPartKind
|
|
228
242
|
*/
|
|
229
243
|
/** @typedef {[SpecifierPartKind, string | number]} SpecifierPart */
|
|
230
244
|
|
|
@@ -236,14 +250,22 @@ const SPECIFIER_PART_KINDS = new Set([
|
|
|
236
250
|
"unserved",
|
|
237
251
|
"base",
|
|
238
252
|
"chunk",
|
|
239
|
-
"cssChunk"
|
|
253
|
+
"cssChunk",
|
|
254
|
+
"repair"
|
|
240
255
|
]);
|
|
241
256
|
|
|
242
257
|
// Only these carry a chunk id, which is the one part value that may be a number.
|
|
243
258
|
const CHUNK_SPECIFIER_PART_KINDS = new Set(["chunk", "cssChunk"]);
|
|
244
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
|
+
|
|
245
264
|
// What the deferred pass scans for — the other half of what the class spells.
|
|
265
|
+
const ANALYZABLE_TOKEN_PREFIX = "./@@webpackAnalyzableChunk:";
|
|
246
266
|
const ANALYZABLE_TOKEN_REGEXP = /\.\/@@webpackAnalyzableChunk:([\w-]+)@@/g;
|
|
267
|
+
// The same token read back out of one quoted specifier.
|
|
268
|
+
const ANALYZABLE_TOKEN_PAYLOAD = /@@webpackAnalyzableChunk:([\w-]+)@@/;
|
|
247
269
|
|
|
248
270
|
// Stands in for the compilation hash inside an otherwise resolved filename, with the
|
|
249
271
|
// requested length when the placeholder asked for one.
|
|
@@ -286,8 +308,7 @@ const PASS_NAME = "analyzableChunkNaming";
|
|
|
286
308
|
/** @import { Source } from "webpack-sources" */
|
|
287
309
|
/** @import Compiler from "./Compiler" */
|
|
288
310
|
/** @import Chunk, { ChunkFilenameTemplate, ChunkId } from "./Chunk" */
|
|
289
|
-
/** @import
|
|
290
|
-
/** @import ChunkGraph from "./ChunkGraph" */
|
|
311
|
+
/** @import ChunkGraph, { ModuleId } from "./ChunkGraph" */
|
|
291
312
|
/** @import Compilation from "./Compilation" */
|
|
292
313
|
/** @import Dependency from "./Dependency" */
|
|
293
314
|
/** @import ModuleGraph from "./ModuleGraph" */
|
|
@@ -331,6 +352,25 @@ const createHashProbeChunk = (chunk, hash, present) => {
|
|
|
331
352
|
return probeChunk;
|
|
332
353
|
};
|
|
333
354
|
|
|
355
|
+
/**
|
|
356
|
+
* A filename function's answer to the stand-in hash, which says what shape the name
|
|
357
|
+
* has before any real hash exists.
|
|
358
|
+
* @param {Exclude<ChunkFilenameTemplate, string>} template the filename function
|
|
359
|
+
* @param {Chunk} chunk the chunk being referenced
|
|
360
|
+
* @param {string} contentHashType which of the chunk's hashes the name reads
|
|
361
|
+
* @param {string} hash the stand-in hash
|
|
362
|
+
* @param {boolean} present whether the chunk is claimed to carry content hashes
|
|
363
|
+
* @returns {string} what the function names it
|
|
364
|
+
*/
|
|
365
|
+
const probeTemplateName = (template, chunk, contentHashType, hash, present) =>
|
|
366
|
+
template({
|
|
367
|
+
chunk: createHashProbeChunk(chunk, hash, present),
|
|
368
|
+
runtime: chunk.runtime,
|
|
369
|
+
contentHashType,
|
|
370
|
+
hash,
|
|
371
|
+
contentHash: hash
|
|
372
|
+
});
|
|
373
|
+
|
|
334
374
|
/**
|
|
335
375
|
* No module id error message.
|
|
336
376
|
* @param {Module} module the module
|
|
@@ -385,6 +425,48 @@ function getGlobalObject(definition) {
|
|
|
385
425
|
return `Object(${trimmed})`;
|
|
386
426
|
}
|
|
387
427
|
|
|
428
|
+
// An async external is a promise, not a module record with an evaluating state.
|
|
429
|
+
const isAsyncExternal = (/** @type {Module} */ module) =>
|
|
430
|
+
Boolean(/** @type {BuildMeta} */ (module.buildMeta).async) &&
|
|
431
|
+
module instanceof getExternalModule();
|
|
432
|
+
|
|
433
|
+
// `createFakeNamespaceObject`'s "merge all properties" bit, the only one that
|
|
434
|
+
// changes which names the namespace it builds carries.
|
|
435
|
+
const MERGE_PROPERTIES_MODE = 2;
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* The imported module decides, never the importer: two importers of one
|
|
439
|
+
* module have to be handed the same namespace object.
|
|
440
|
+
* @param {Module} module the imported module
|
|
441
|
+
* @returns {boolean} true when its namespace has to be a spec exotic object
|
|
442
|
+
*/
|
|
443
|
+
const usesSpecNamespaceObject = (module) =>
|
|
444
|
+
Boolean(module.buildInfo && module.buildInfo.specNamespaceObject);
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* A module with no ESM namespace of its own — JSON, text, CommonJS — has one
|
|
448
|
+
* synthesized at each import site, so there the importer decides.
|
|
449
|
+
* @param {Module=} originModule the module the import is emitted into
|
|
450
|
+
* @returns {boolean} true when a namespace synthesized here has to be a spec object
|
|
451
|
+
*/
|
|
452
|
+
const synthesizesSpecNamespaceObject = (originModule) =>
|
|
453
|
+
originModule !== undefined && usesSpecNamespaceObject(originModule);
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Names the record a synthesized namespace belongs to and the shape it is built in,
|
|
457
|
+
* so every importer of one module reaches the same object and a reloaded module is
|
|
458
|
+
* not handed the namespace of the exports it replaced.
|
|
459
|
+
* @param {ModuleId | null} moduleId id of the imported module
|
|
460
|
+
* @param {number} mode the createFakeNamespaceObject mode the namespace is built with
|
|
461
|
+
* @returns {string} the arguments identifying it, ready to append to the call
|
|
462
|
+
*/
|
|
463
|
+
const synthesizedNamespaceOwner = (moduleId, mode) =>
|
|
464
|
+
moduleId === null
|
|
465
|
+
? ""
|
|
466
|
+
: `, ${RuntimeGlobals.moduleCache}[${JSON.stringify(moduleId)}], ${
|
|
467
|
+
mode & MERGE_PROPERTIES_MODE
|
|
468
|
+
}`;
|
|
469
|
+
|
|
388
470
|
class RuntimeTemplate {
|
|
389
471
|
/**
|
|
390
472
|
* Creates an instance of RuntimeTemplate.
|
|
@@ -404,8 +486,8 @@ class RuntimeTemplate {
|
|
|
404
486
|
(getGlobalObject(outputOptions.globalObject));
|
|
405
487
|
/** @type {string} */
|
|
406
488
|
this.contentHashReplacement = "X".repeat(outputOptions.hashDigestLength);
|
|
407
|
-
/** @type {
|
|
408
|
-
this.
|
|
489
|
+
/** @type {Set<string>} */
|
|
490
|
+
this._analyzableRepairedAssets = new Set();
|
|
409
491
|
/** @type {WeakMap<Chunk, boolean>} */
|
|
410
492
|
this._chunkNamedWithoutContent = new WeakMap();
|
|
411
493
|
/** @type {WeakMap<Chunk, string>} */
|
|
@@ -424,16 +506,20 @@ class RuntimeTemplate {
|
|
|
424
506
|
this._publicPathClimbText = undefined;
|
|
425
507
|
/** @type {WeakMap<Chunk, Placement>} */
|
|
426
508
|
this._placementByChunk = new WeakMap();
|
|
509
|
+
/** @type {WeakMap<Chunk, string>} */
|
|
510
|
+
this._hotUpdateUndoByChunk = new WeakMap();
|
|
511
|
+
/** @type {string | undefined} */
|
|
512
|
+
this._hotUpdateShapeText = undefined;
|
|
427
513
|
/** @type {Map<string, string | null | undefined>} */
|
|
428
514
|
this._entryBaseUriByRuntime = new Map();
|
|
429
|
-
/** @type {
|
|
430
|
-
this.
|
|
431
|
-
/** @type {
|
|
432
|
-
this.
|
|
515
|
+
/** @type {WasmGroups | undefined} */
|
|
516
|
+
this._wasmGroupsValue = undefined;
|
|
517
|
+
/** @type {string[] | undefined} */
|
|
518
|
+
this._analyzableBailoutSink = undefined;
|
|
519
|
+
/** @type {Module | undefined} */
|
|
520
|
+
this._analyzableGeneratingModule = undefined;
|
|
433
521
|
/** @type {Map<string, boolean> | undefined} */
|
|
434
522
|
this._wasmAnchorKnownByGroup = undefined;
|
|
435
|
-
/** @type {Map<string, boolean> | undefined} */
|
|
436
|
-
this._wasmGroupOnlyFetchesMap = undefined;
|
|
437
523
|
}
|
|
438
524
|
|
|
439
525
|
isIIFE() {
|
|
@@ -530,6 +616,10 @@ class RuntimeTemplate {
|
|
|
530
616
|
return this.outputOptions.environment.generator;
|
|
531
617
|
}
|
|
532
618
|
|
|
619
|
+
supportsTopLevelAwait() {
|
|
620
|
+
return this.outputOptions.environment.topLevelAwait;
|
|
621
|
+
}
|
|
622
|
+
|
|
533
623
|
supportsOptionalChaining() {
|
|
534
624
|
return this.outputOptions.environment.optionalChaining;
|
|
535
625
|
}
|
|
@@ -578,6 +668,41 @@ class RuntimeTemplate {
|
|
|
578
668
|
return this.outputOptions.environment.modulePreload;
|
|
579
669
|
}
|
|
580
670
|
|
|
671
|
+
/**
|
|
672
|
+
* Whether the deferred fill rewrote a chunk whose hashed name would otherwise go
|
|
673
|
+
* stale, which `RealContentHashPlugin` reads to run — and to repair `[chunkhash]`
|
|
674
|
+
* names — where `optimization.realContentHash` did not ask for it.
|
|
675
|
+
* @returns {boolean} true once the fill has marked such a chunk
|
|
676
|
+
*/
|
|
677
|
+
needsAnalyzableRepair() {
|
|
678
|
+
return this._analyzableRepairedAssets.size > 0;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* The assets the deferred fill rewrote under a name that has to be repaired: an
|
|
683
|
+
* on-demand repair renames only these and whatever names them.
|
|
684
|
+
* @returns {ReadonlySet<string>} their names
|
|
685
|
+
*/
|
|
686
|
+
analyzableRepairedAssets() {
|
|
687
|
+
return this._analyzableRepairedAssets;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* The `devtool` value wrapping a javascript module in `eval(...)`, read through both
|
|
692
|
+
* spellings — a plain string, and the per-asset-type array.
|
|
693
|
+
* @returns {string | undefined} the value, or undefined when no devtool wraps modules
|
|
694
|
+
*/
|
|
695
|
+
_evalWrappingDevtool() {
|
|
696
|
+
const { devtool } = this.compilation.options;
|
|
697
|
+
const items = Array.isArray(devtool)
|
|
698
|
+
? devtool
|
|
699
|
+
: [{ type: "all", use: devtool }];
|
|
700
|
+
for (const { type, use } of items) {
|
|
701
|
+
if (type !== "all" && type !== "javascript") continue;
|
|
702
|
+
if (typeof use === "string" && use.includes("eval")) return use;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
581
706
|
/**
|
|
582
707
|
* Whether a reference a foreign bundler can follow without running webpack's runtime
|
|
583
708
|
* may be emitted — the one question every caller asks, in the form it is asking for:
|
|
@@ -620,131 +745,88 @@ class RuntimeTemplate {
|
|
|
620
745
|
: undefined;
|
|
621
746
|
// A reassigned `__webpack_public_path__` cannot reach a baked literal, and `.p`
|
|
622
747
|
// belongs to a runtime, so only the runtimes it reaches keep the runtime form.
|
|
623
|
-
// `url-inline` is unaffected:
|
|
624
|
-
// the reassigned value at the call site rather than through the wrapper.
|
|
748
|
+
// `url-inline` is unaffected: it reads the value at the call site.
|
|
625
749
|
if (
|
|
626
750
|
form !== "url-inline" &&
|
|
627
751
|
APIPlugin.runtimeUsesPublicPathOverride(
|
|
628
752
|
this.compilation,
|
|
629
753
|
scoped ? chunkGraph : undefined,
|
|
630
|
-
placedModule
|
|
754
|
+
placedModule,
|
|
755
|
+
runtime
|
|
631
756
|
)
|
|
632
757
|
) {
|
|
633
|
-
this._analyzableBailout(
|
|
758
|
+
return this._analyzableBailout(
|
|
634
759
|
module,
|
|
635
|
-
"__webpack_public_path__ is reassigned in a runtime this module belongs to"
|
|
760
|
+
"__webpack_public_path__ is reassigned in a runtime this module belongs to",
|
|
761
|
+
false
|
|
636
762
|
);
|
|
637
|
-
return false;
|
|
638
763
|
}
|
|
639
764
|
|
|
640
765
|
if (form === "import") {
|
|
641
766
|
// Read through a native `import()`, or it is not this feature at all.
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
`output.chunkFormat is ${JSON.stringify(outputOptions.chunkFormat)}, so chunks are not read through a native import()`
|
|
646
|
-
);
|
|
647
|
-
return false;
|
|
648
|
-
}
|
|
649
|
-
if (outputOptions.importFunctionName !== "import") {
|
|
650
|
-
this._analyzableBailout(
|
|
651
|
-
module,
|
|
652
|
-
`output.importFunctionName is ${JSON.stringify(outputOptions.importFunctionName)}, so the call site is not a native import()`
|
|
653
|
-
);
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
|
-
// A worker loading its own chunks some other way keeps that runtime; one on
|
|
657
|
-
// `import` uses the same ESM loader as the main graph, so it can be analyzable.
|
|
658
|
-
for (const originChunk of /** @type {ChunkGraph} */ (
|
|
659
|
-
chunkGraph
|
|
660
|
-
).getModuleChunksIterable(/** @type {Module} */ (placedModule))) {
|
|
661
|
-
const entryOptions = originChunk.getEntryOptions();
|
|
662
|
-
if (!entryOptions || !entryOptions.worker) continue;
|
|
663
|
-
// `WorkerAndWorkletPlugin` always seeds this from `output.workerChunkLoading`.
|
|
664
|
-
if (entryOptions.chunkLoading !== "import") {
|
|
665
|
-
this._analyzableBailout(
|
|
666
|
-
module,
|
|
667
|
-
`this worker loads its chunks with ${JSON.stringify(entryOptions.chunkLoading)}, not "import"`
|
|
668
|
-
);
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
767
|
+
const outputReason = this._chunkImportOutputReason();
|
|
768
|
+
if (outputReason !== null) {
|
|
769
|
+
return this._analyzableBailout(module, outputReason, false);
|
|
671
770
|
}
|
|
771
|
+
// A worker loading its own chunks some other way needs no answer here: it gets
|
|
772
|
+
// a chunk loader of its own, and only the ESM one asks this.
|
|
672
773
|
return true;
|
|
673
774
|
}
|
|
674
775
|
|
|
675
|
-
// `url-inline` asks whether the file can be named at the call site
|
|
676
|
-
// its `.p + <file>` fallback spells that without `import.meta
|
|
677
|
-
// below
|
|
776
|
+
// `url-inline` asks only whether the file can be named at the call site, and
|
|
777
|
+
// its `.p + <file>` fallback spells that without `import.meta`, so the gate
|
|
778
|
+
// below does not rule it out.
|
|
779
|
+
|
|
780
|
+
// `environment.module` is deliberately not consulted: ESM output writes
|
|
781
|
+
// `import.meta` regardless, so the url forms match what the rest of the
|
|
782
|
+
// bundle already assumes the target reads.
|
|
678
783
|
if (form === "url-inline") return true;
|
|
679
|
-
// `import.meta` is ESM syntax the target has to read. A chunk `import()` is
|
|
680
|
-
// emitted by the module chunk loader either way, so only the url forms check.
|
|
681
|
-
if (!this.supportsEcmaScriptModuleSyntax()) {
|
|
682
|
-
this._analyzableBailout(
|
|
683
|
-
module,
|
|
684
|
-
"output.environment.module is false, so the target does not read the import.meta this form needs"
|
|
685
|
-
);
|
|
686
|
-
return false;
|
|
687
|
-
}
|
|
688
784
|
// `eval` devtool wraps each module in `eval(...)`, where `import.meta` is a
|
|
689
785
|
// syntax error. Runtime modules are emitted beside them, never wrapped.
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
devtool.includes("eval")
|
|
695
|
-
) {
|
|
696
|
-
this._analyzableBailout(
|
|
786
|
+
const evalDevtool =
|
|
787
|
+
form === "url-runtime" ? undefined : this._evalWrappingDevtool();
|
|
788
|
+
if (evalDevtool !== undefined) {
|
|
789
|
+
return this._analyzableBailout(
|
|
697
790
|
module,
|
|
698
|
-
`devtool ${JSON.stringify(
|
|
791
|
+
`devtool ${JSON.stringify(evalDevtool)} wraps the module in eval(), where import.meta does not parse`,
|
|
792
|
+
false
|
|
699
793
|
);
|
|
700
|
-
return false;
|
|
701
794
|
}
|
|
702
795
|
if (form === "url" || form === "url-runtime") return true;
|
|
703
796
|
// A bare relative URL is what `__webpack_require__.p + path` means only under an
|
|
704
797
|
// `auto` public path; anything else has to be baked, which is the "wasm" form.
|
|
705
798
|
if (form === "wasm-relative") {
|
|
706
799
|
if (outputOptions.publicPath === "auto") return true;
|
|
707
|
-
this._analyzableBailout(
|
|
800
|
+
return this._analyzableBailout(
|
|
708
801
|
module,
|
|
709
|
-
"output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to"
|
|
802
|
+
"output.publicPath is set, so a bare relative url no longer means what the public path would have resolved to",
|
|
803
|
+
false
|
|
710
804
|
);
|
|
711
|
-
return false;
|
|
712
805
|
}
|
|
713
806
|
|
|
714
807
|
// The rest is the `"wasm"` form: whether the whole binary url can be spelled
|
|
715
808
|
// here, rather than built at runtime under an `import.meta.url` base.
|
|
716
|
-
const { publicPath
|
|
809
|
+
const { publicPath } = outputOptions;
|
|
717
810
|
if (publicPath !== "auto") {
|
|
718
811
|
// A public path that needs no base names the same place from the chunk as from
|
|
719
812
|
// the document, so a literal spells what `fetch` would have reached.
|
|
720
813
|
if (this._publicPathNeedsNoBase()) {
|
|
721
814
|
// Settled no earlier than the hash it reads or is called with, so it is
|
|
722
815
|
// baked only where the deferred pass may finish it.
|
|
723
|
-
if (this._resolvePublicPathPrefix(publicPath
|
|
816
|
+
if (this._resolvePublicPathPrefix(publicPath) === null) {
|
|
724
817
|
return false;
|
|
725
818
|
}
|
|
726
819
|
} else if (
|
|
727
820
|
this._anyWasmChunkFetches(runtime) &&
|
|
728
821
|
!this._wasmFetchAnchorIsKnown(runtime)
|
|
729
822
|
) {
|
|
730
|
-
this._analyzableBailout(
|
|
823
|
+
return this._analyzableBailout(
|
|
731
824
|
module,
|
|
732
|
-
"output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from"
|
|
825
|
+
"output.publicPath needs a base, and no one path back to the document fits every chunk `fetch` reads it from",
|
|
826
|
+
false
|
|
733
827
|
);
|
|
734
|
-
return false;
|
|
735
828
|
}
|
|
736
829
|
}
|
|
737
|
-
// The compilation hash is settled after code generation, so a name carrying one
|
|
738
|
-
// is baked only where the deferred pass can fill it in. `[hash]` is the module's
|
|
739
|
-
// own here, which code generation already knows.
|
|
740
|
-
if (
|
|
741
|
-
getTemplatedPathPlugin()
|
|
742
|
-
.getPresentKinds(/** @type {string} */ (webassemblyModuleFilename))
|
|
743
|
-
.has("fullhash") &&
|
|
744
|
-
!this._canDeferOrBakeFullHash(true, undefined, module)
|
|
745
|
-
) {
|
|
746
|
-
return false;
|
|
747
|
-
}
|
|
748
830
|
return true;
|
|
749
831
|
}
|
|
750
832
|
|
|
@@ -753,45 +835,107 @@ class RuntimeTemplate {
|
|
|
753
835
|
* the channel `ModuleConcatenationPlugin` already reports through, so it reaches
|
|
754
836
|
* `stats.optimizationBailout`. Silent unless the build asked for ESM output, where
|
|
755
837
|
* alone the answer is actionable; deduplicated because a module may write many.
|
|
838
|
+
* Answers with `answer` so a caller states the refusal and its reason at once —
|
|
839
|
+
* `false` where it answers a question, `null` where it was building a specifier.
|
|
840
|
+
* @template {false | null} T
|
|
756
841
|
* @param {Module | undefined} module the module the reference is emitted into
|
|
757
842
|
* @param {string} reason why no literal could be baked
|
|
843
|
+
* @param {T} answer what the caller hands back
|
|
844
|
+
* @returns {T} that answer
|
|
845
|
+
*/
|
|
846
|
+
_analyzableBailout(module, reason, answer) {
|
|
847
|
+
if (module !== undefined && this.outputOptions.module) {
|
|
848
|
+
// Recorded on the module whose code is being generated, which is the one a
|
|
849
|
+
// cached result is restored for — an inner module of a concatenation is not.
|
|
850
|
+
const target = this._analyzableGeneratingModule || module;
|
|
851
|
+
const text = `${ANALYZABLE_BAILOUT_PREFIX}${reason}`;
|
|
852
|
+
const bailouts =
|
|
853
|
+
this.compilation.moduleGraph.getOptimizationBailout(target);
|
|
854
|
+
if (!bailouts.includes(text)) bailouts.push(text);
|
|
855
|
+
// Each generation records its own: another runtime's result may be all the
|
|
856
|
+
// cache restores later, so what the graph holds must not hide a reason.
|
|
857
|
+
if (this._analyzableGeneratingModule !== undefined) {
|
|
858
|
+
// The sink exists only once a reason is recorded, so a module that
|
|
859
|
+
// bakes every reference — nearly all of them — allocates nothing here.
|
|
860
|
+
const sink =
|
|
861
|
+
this._analyzableBailoutSink || (this._analyzableBailoutSink = []);
|
|
862
|
+
if (!sink.includes(reason)) sink.push(reason);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
return answer;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Names the module whose code generation starts, so the reasons its references
|
|
870
|
+
* record are handed back by `finishAnalyzableBailouts` and attributed to it.
|
|
871
|
+
* @param {Module} module the module being generated
|
|
758
872
|
* @returns {void}
|
|
759
873
|
*/
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
874
|
+
beginAnalyzableBailouts(module) {
|
|
875
|
+
this._analyzableGeneratingModule = module;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
/**
|
|
879
|
+
* Ends the collection `beginAnalyzableBailouts` started, so the reasons can be
|
|
880
|
+
* stored beside the result and reapplied when the cache restores it.
|
|
881
|
+
* @returns {string[] | undefined} the reasons recorded since, or undefined for none
|
|
882
|
+
*/
|
|
883
|
+
finishAnalyzableBailouts() {
|
|
884
|
+
const sink = this._analyzableBailoutSink;
|
|
885
|
+
this._analyzableGeneratingModule = undefined;
|
|
886
|
+
this._analyzableBailoutSink = undefined;
|
|
887
|
+
return sink;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Reapplies the bailouts a cached code generation result was stored with, so a
|
|
892
|
+
* restored module reports the same reasons a generated one does.
|
|
893
|
+
* @param {Module} module the module the result was restored for
|
|
894
|
+
* @param {string[]} reasons the reasons stored beside it
|
|
895
|
+
* @returns {void}
|
|
896
|
+
*/
|
|
897
|
+
restoreAnalyzableBailouts(module, reasons) {
|
|
763
898
|
const bailouts =
|
|
764
899
|
this.compilation.moduleGraph.getOptimizationBailout(module);
|
|
765
|
-
for (const
|
|
766
|
-
|
|
900
|
+
for (const reason of reasons) {
|
|
901
|
+
const text = `${ANALYZABLE_BAILOUT_PREFIX}${reason}`;
|
|
902
|
+
if (!bailouts.includes(text)) bailouts.push(text);
|
|
767
903
|
}
|
|
768
|
-
bailouts.push(text);
|
|
769
904
|
}
|
|
770
905
|
|
|
771
906
|
/**
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
* place — with a name like `[name].js` there is nothing to go stale. Asked of the
|
|
777
|
-
* names the chunks actually carry rather than of `output`, so a template nothing is
|
|
778
|
-
* emitted under does not rule the rewrite out and a `chunk.filenameTemplate` does
|
|
779
|
-
* not slip past it.
|
|
780
|
-
* @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into; omit
|
|
781
|
-
* where the answer has to hold for the whole compilation, as it does for a gate a
|
|
782
|
-
* runtime module asks from the other end
|
|
783
|
-
* @returns {boolean} true when deferring is safe
|
|
907
|
+
* The reasons a module's references keep the runtime form, as recorded while its
|
|
908
|
+
* code was generated.
|
|
909
|
+
* @param {Module} module the module, a runtime module included
|
|
910
|
+
* @returns {string[]} the reasons, none where every reference bakes
|
|
784
911
|
*/
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
912
|
+
analyzableBailoutsOf(module) {
|
|
913
|
+
/** @type {string[]} */
|
|
914
|
+
const reasons = [];
|
|
915
|
+
for (const text of this.compilation.moduleGraph.getOptimizationBailout(
|
|
916
|
+
module
|
|
917
|
+
)) {
|
|
918
|
+
if (
|
|
919
|
+
typeof text === "string" &&
|
|
920
|
+
text.startsWith(ANALYZABLE_BAILOUT_PREFIX)
|
|
921
|
+
) {
|
|
922
|
+
reasons.push(text.slice(ANALYZABLE_BAILOUT_PREFIX.length));
|
|
792
923
|
}
|
|
793
|
-
return this._javascriptNamedWithoutContent;
|
|
794
924
|
}
|
|
925
|
+
return reasons;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* Whether a name that code generation cannot settle may be reserved as a stand-in
|
|
930
|
+
* and filled in once the hashes exist without a repair behind it. Substituting
|
|
931
|
+
* rewrites a chunk after its own content hash was taken, so either no emitted
|
|
932
|
+
* javascript may be named by its content — with a name like `[name].js` there is
|
|
933
|
+
* nothing to go stale — or `RealContentHashPlugin` has to bring the two back in
|
|
934
|
+
* line, which is what a name this says no to gets: see `_needsRepair`.
|
|
935
|
+
* @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
|
|
936
|
+
* @returns {boolean} true when no name moves with the bytes the fill leaves
|
|
937
|
+
*/
|
|
938
|
+
_canDeferAnalyzableName(chunks) {
|
|
795
939
|
let found = false;
|
|
796
940
|
for (const chunk of chunks) {
|
|
797
941
|
found = true;
|
|
@@ -802,16 +946,15 @@ class RuntimeTemplate {
|
|
|
802
946
|
}
|
|
803
947
|
|
|
804
948
|
/**
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
*
|
|
808
|
-
*
|
|
809
|
-
* @
|
|
949
|
+
* Whether a stand-in written into `chunks` needs the repair pass behind it: their
|
|
950
|
+
* hashed names would otherwise go stale once the fill moves their bytes. The pass
|
|
951
|
+
* is `RealContentHashPlugin`, run on demand where `optimization.realContentHash`
|
|
952
|
+
* did not ask for it, and repairing `[chunkhash]` names too while it is at it.
|
|
953
|
+
* @param {Iterable<Chunk>} chunks the chunks the stand-in is written into
|
|
954
|
+
* @returns {boolean} true when the fill has to mark the name for repair
|
|
810
955
|
*/
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this._analyzableBailout(module, DEFER_BAILOUT);
|
|
814
|
-
return false;
|
|
956
|
+
_needsRepair(chunks) {
|
|
957
|
+
return !this._canDeferAnalyzableName(chunks);
|
|
815
958
|
}
|
|
816
959
|
|
|
817
960
|
/**
|
|
@@ -819,37 +962,28 @@ class RuntimeTemplate {
|
|
|
819
962
|
* and a stand-in for the deferred pass where they do not.
|
|
820
963
|
* @param {SpecifierPart[]} parts the whole specifier
|
|
821
964
|
* @param {Iterable<Chunk>} chunks the chunks it is written into
|
|
822
|
-
* @
|
|
823
|
-
* @returns {string | null} it already quoted, or `null` when no stand-in may be
|
|
824
|
-
* reserved
|
|
965
|
+
* @returns {string} it already quoted
|
|
825
966
|
*/
|
|
826
|
-
_specifierOf(parts, chunks
|
|
967
|
+
_specifierOf(parts, chunks) {
|
|
827
968
|
const text = literalText(parts);
|
|
828
969
|
if (text !== null) return toJsStringLiteral(text);
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
) {
|
|
836
|
-
return null;
|
|
837
|
-
}
|
|
838
|
-
return toJsStringLiteral(this._reserveAnalyzableSpecifier(parts));
|
|
970
|
+
// One built out of the compilation hash moves its chunk into the round after
|
|
971
|
+
// that hash, where the name is taken from the filled bytes anyway.
|
|
972
|
+
const repair = !this._partsBakeFullHash(parts) && this._needsRepair(chunks);
|
|
973
|
+
return toJsStringLiteral(
|
|
974
|
+
this._reserveAnalyzableSpecifier(this._markedForRepair(repair, parts))
|
|
975
|
+
);
|
|
839
976
|
}
|
|
840
977
|
|
|
841
978
|
/**
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
* @
|
|
847
|
-
* @param {Iterable<Chunk>=} chunks the chunks the stand-in is written into
|
|
848
|
-
* @param {Module=} module the module the reference is emitted into
|
|
849
|
-
* @returns {boolean} true when deferring is safe
|
|
979
|
+
* The parts a stand-in is reserved with, marked where the name it lands in has to
|
|
980
|
+
* be repaired after the fill.
|
|
981
|
+
* @param {boolean} repair what `_needsRepair` answered
|
|
982
|
+
* @param {SpecifierPart[]} parts what the stand-in resolves to
|
|
983
|
+
* @returns {SpecifierPart[]} the parts, marked where the repair is needed
|
|
850
984
|
*/
|
|
851
|
-
|
|
852
|
-
return
|
|
985
|
+
_markedForRepair(repair, parts) {
|
|
986
|
+
return repair ? [["repair", ""], ...parts] : parts;
|
|
853
987
|
}
|
|
854
988
|
|
|
855
989
|
/**
|
|
@@ -861,9 +995,7 @@ class RuntimeTemplate {
|
|
|
861
995
|
*/
|
|
862
996
|
_partsBakeFullHash(parts) {
|
|
863
997
|
for (const [kind, value] of parts) {
|
|
864
|
-
if (kind
|
|
865
|
-
return true;
|
|
866
|
-
}
|
|
998
|
+
if (FULL_HASH_PART_KINDS.has(kind)) return true;
|
|
867
999
|
if (kind === "literal" && this._hasReservedFullHash(String(value))) {
|
|
868
1000
|
return true;
|
|
869
1001
|
}
|
|
@@ -962,95 +1094,82 @@ class RuntimeTemplate {
|
|
|
962
1094
|
const base = this.analyzableUrlReadsBaseUri()
|
|
963
1095
|
? this.entryBaseUri(runtime)
|
|
964
1096
|
: undefined;
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
);
|
|
1037
|
-
return null;
|
|
1038
|
-
}
|
|
1039
|
-
if (text !== null) return toJsStringLiteral(resolved.href);
|
|
1040
|
-
if (!this._canDeferOrBail(chunks, module)) return null;
|
|
1041
|
-
return toJsStringLiteral(
|
|
1042
|
-
this._reserveAnalyzableSpecifier([
|
|
1097
|
+
// No base of its own: the name is spelled against the output root, as a chunk is.
|
|
1098
|
+
if (base === undefined) {
|
|
1099
|
+
return this._getAnalyzableFileSpecifier(
|
|
1100
|
+
module,
|
|
1101
|
+
chunkGraph,
|
|
1102
|
+
[["literal", filename]],
|
|
1103
|
+
true
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
if (base === null) {
|
|
1107
|
+
return this._analyzableBailout(
|
|
1108
|
+
module,
|
|
1109
|
+
"the entries this module is generated for set different baseUri values, so no one url resolves for all of them",
|
|
1110
|
+
null
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
// A relative one is no base of its own: the runtime reads it against the
|
|
1114
|
+
// chunk, so the literal spells it there rather than resolving against it.
|
|
1115
|
+
if (isChunkRelativeBaseUri(base)) {
|
|
1116
|
+
return this._getAnalyzableFileSpecifier(
|
|
1117
|
+
module,
|
|
1118
|
+
chunkGraph,
|
|
1119
|
+
[["literal", filename]],
|
|
1120
|
+
true,
|
|
1121
|
+
base
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
const chunks = this._moduleChunks(module, chunkGraph);
|
|
1125
|
+
const parts = this._resolvePublicPathPrefix(publicPath);
|
|
1126
|
+
if (parts === null) return null;
|
|
1127
|
+
// A protocol-relative base names a host but no scheme, and the runtime reads
|
|
1128
|
+
// it against the very url this literal resolves against, so it may stay that
|
|
1129
|
+
// way. Nothing walks back to the output root: the base replaces it.
|
|
1130
|
+
if (base.startsWith("//")) {
|
|
1131
|
+
return this._specifierOf(
|
|
1132
|
+
[["literal", base], ...rootedParts(parts), ["literal", filename]],
|
|
1133
|
+
chunks
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
if (!isAbsoluteBaseUri(base)) {
|
|
1137
|
+
return this._analyzableBailout(
|
|
1138
|
+
module,
|
|
1139
|
+
`an entry sets a baseUri of ${JSON.stringify(base)}, whose scheme names no base anything can be resolved against`,
|
|
1140
|
+
null
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
// Resolved here rather than against the output root, and only an absolute base
|
|
1144
|
+
// settles it — a relative one has no base of its own to be read against.
|
|
1145
|
+
const spelled = literalText(parts);
|
|
1146
|
+
// A hash the deferred pass still has to fill in cannot be resolved against the
|
|
1147
|
+
// base here: the fill would land inside an already-resolved url, where a hash
|
|
1148
|
+
// opening with a letter reads as a scheme and drops the base entirely.
|
|
1149
|
+
const text =
|
|
1150
|
+
spelled !== null && !this._hasReservedFullHash(spelled) ? spelled : null;
|
|
1151
|
+
/** @type {URL} */
|
|
1152
|
+
let resolved;
|
|
1153
|
+
try {
|
|
1154
|
+
// Empty where only the deferred pass can spell the rest, which still settles
|
|
1155
|
+
// whether the base itself is one anything may be resolved against.
|
|
1156
|
+
resolved = new URL(text === null ? "" : text + filename, base);
|
|
1157
|
+
} catch (_error) {
|
|
1158
|
+
return this._analyzableBailout(
|
|
1159
|
+
module,
|
|
1160
|
+
`an entry sets a baseUri of ${JSON.stringify(base)}, which is not absolute, so no url can be resolved against it here`,
|
|
1161
|
+
null
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1164
|
+
if (text !== null) return toJsStringLiteral(resolved.href);
|
|
1165
|
+
return toJsStringLiteral(
|
|
1166
|
+
this._reserveAnalyzableSpecifier(
|
|
1167
|
+
this._markedForRepair(this._needsRepair(chunks), [
|
|
1043
1168
|
["base", base],
|
|
1044
1169
|
...parts,
|
|
1045
1170
|
["literal", filename]
|
|
1046
1171
|
])
|
|
1047
|
-
)
|
|
1048
|
-
}
|
|
1049
|
-
return this._getAnalyzableFileSpecifier(
|
|
1050
|
-
module,
|
|
1051
|
-
chunkGraph,
|
|
1052
|
-
[["literal", filename]],
|
|
1053
|
-
true
|
|
1172
|
+
)
|
|
1054
1173
|
);
|
|
1055
1174
|
}
|
|
1056
1175
|
|
|
@@ -1072,10 +1191,9 @@ class RuntimeTemplate {
|
|
|
1072
1191
|
let base;
|
|
1073
1192
|
let found = false;
|
|
1074
1193
|
for (const chunk of this.compilation.chunks) {
|
|
1075
|
-
//
|
|
1076
|
-
//
|
|
1077
|
-
//
|
|
1078
|
-
// chunk already share the base it sets, however their descriptors differ.
|
|
1194
|
+
// A literal must agree with the one value `BaseUriRuntimeModule` writes, and
|
|
1195
|
+
// that reads the entry options off the chunk it is emitted into, so only a
|
|
1196
|
+
// chunk carrying a runtime has a say.
|
|
1079
1197
|
if (!chunk.hasRuntime()) continue;
|
|
1080
1198
|
const entryOptions = chunk.getEntryOptions();
|
|
1081
1199
|
// An entry this code cannot run under has no say in the base it resolves to.
|
|
@@ -1121,55 +1239,119 @@ class RuntimeTemplate {
|
|
|
1121
1239
|
return publicPath.includes("[") ? undefined : publicPath;
|
|
1122
1240
|
}
|
|
1123
1241
|
|
|
1242
|
+
/**
|
|
1243
|
+
* Runtime keys grouped by the binaries they share, with what the entries of each
|
|
1244
|
+
* group asked for. Code generation runs once for runtimes a module hashes alike in,
|
|
1245
|
+
* and nothing in a binary's hash knows which loader will read it — so a binary two
|
|
1246
|
+
* runtimes reach carries one shape into both, and a third runtime sharing another
|
|
1247
|
+
* binary with either is pulled in after them. Only an entry names a loader; every
|
|
1248
|
+
* other chunk of the runtime is served by the one its entry asked for. Asked of the
|
|
1249
|
+
* same modules the loaders are created for, and only once per compilation.
|
|
1250
|
+
* @returns {WasmGroups} the grouping, and which groups fetch
|
|
1251
|
+
*/
|
|
1252
|
+
_wasmGroups() {
|
|
1253
|
+
if (this._wasmGroupsValue === undefined) {
|
|
1254
|
+
const { chunkGraph, chunks, modules } = this.compilation;
|
|
1255
|
+
/** @type {Map<string, string>} */
|
|
1256
|
+
const parent = new Map();
|
|
1257
|
+
/**
|
|
1258
|
+
* @param {string} key runtime key
|
|
1259
|
+
* @returns {string} the key naming its group
|
|
1260
|
+
*/
|
|
1261
|
+
const find = (key) => {
|
|
1262
|
+
let root = key;
|
|
1263
|
+
let seen = parent.get(root);
|
|
1264
|
+
while (seen !== undefined && seen !== root) {
|
|
1265
|
+
root = seen;
|
|
1266
|
+
seen = parent.get(root);
|
|
1267
|
+
}
|
|
1268
|
+
// Path compression keeps a long share chain from costing more than once.
|
|
1269
|
+
let walk = key;
|
|
1270
|
+
let next = parent.get(walk);
|
|
1271
|
+
while (next !== undefined && next !== root) {
|
|
1272
|
+
parent.set(walk, root);
|
|
1273
|
+
walk = next;
|
|
1274
|
+
next = parent.get(walk);
|
|
1275
|
+
}
|
|
1276
|
+
return root;
|
|
1277
|
+
};
|
|
1278
|
+
/** @type {string[]} */
|
|
1279
|
+
const keys = [];
|
|
1280
|
+
for (const module of modules) {
|
|
1281
|
+
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1282
|
+
keys.length = 0;
|
|
1283
|
+
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
|
1284
|
+
forEachRuntime(runtime, (key) => {
|
|
1285
|
+
keys.push(/** @type {string} */ (key));
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
for (const key of keys) if (!parent.has(key)) parent.set(key, key);
|
|
1289
|
+
// Every runtime this binary reaches answers with the first one.
|
|
1290
|
+
for (let i = 1; i < keys.length; i++) {
|
|
1291
|
+
parent.set(find(keys[i]), find(keys[0]));
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
// Flattened once, so a lookup is a single `get` rather than a chain walk.
|
|
1295
|
+
for (const key of parent.keys()) parent.set(key, find(key));
|
|
1296
|
+
/**
|
|
1297
|
+
* @param {string} key a runtime key
|
|
1298
|
+
* @returns {string} the group it answers with, or itself when it shares nothing
|
|
1299
|
+
*/
|
|
1300
|
+
const groupOf = (key) => {
|
|
1301
|
+
const group = parent.get(key);
|
|
1302
|
+
// An entry named "" makes "" a runtime key, so test absence, not a falsy value.
|
|
1303
|
+
return group === undefined ? key : group;
|
|
1304
|
+
};
|
|
1305
|
+
/** @type {Set<string>} */
|
|
1306
|
+
const fetching = new Set();
|
|
1307
|
+
/** @type {Map<string, boolean>} */
|
|
1308
|
+
const onlyFetching = new Map();
|
|
1309
|
+
for (const chunk of chunks) {
|
|
1310
|
+
if (!chunk.getEntryOptions()) continue;
|
|
1311
|
+
const fetches = this._chunkWasmLoading(chunk) === "fetch";
|
|
1312
|
+
forEachRuntime(chunk.runtime, (key) => {
|
|
1313
|
+
const group = groupOf(/** @type {string} */ (key));
|
|
1314
|
+
if (fetches) fetching.add(group);
|
|
1315
|
+
onlyFetching.set(group, onlyFetching.get(group) !== false && fetches);
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
this._wasmGroupsValue = { groupOf, fetching, onlyFetching };
|
|
1319
|
+
}
|
|
1320
|
+
return this._wasmGroupsValue;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* @param {RuntimeSpec} runtime the runtime being asked about
|
|
1325
|
+
* @returns {string[]} the wasm runtime groups it reaches
|
|
1326
|
+
*/
|
|
1327
|
+
_wasmGroupsOf(runtime) {
|
|
1328
|
+
const { groupOf } = this._wasmGroups();
|
|
1329
|
+
/** @type {string[]} */
|
|
1330
|
+
const reached = [];
|
|
1331
|
+
forEachRuntime(runtime, (key) => {
|
|
1332
|
+
reached.push(groupOf(/** @type {string} */ (key)));
|
|
1333
|
+
});
|
|
1334
|
+
return reached;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1124
1337
|
/**
|
|
1125
1338
|
* Whether a chunk loads WebAssembly through `fetch`, which is the only loader the
|
|
1126
1339
|
* public path reaches: `readFile` resolves the binary's name against the chunk it is
|
|
1127
1340
|
* read from, exactly as a baked literal does, so a public path is irrelevant to it.
|
|
1128
|
-
* Answered per
|
|
1341
|
+
* Answered per group rather than per chunk on purpose — a module's generated source
|
|
1129
1342
|
* and the runtime module of every chunk holding it have to agree on the shape, and
|
|
1130
|
-
* they ask from opposite ends; one loader serves a whole
|
|
1131
|
-
*
|
|
1132
|
-
* told apart, the answer covers the compilation.
|
|
1343
|
+
* they ask from opposite ends; one loader serves a whole group, so that is the finest
|
|
1344
|
+
* scope on which they can. Without a runtime the answer covers the compilation.
|
|
1133
1345
|
* @param {RuntimeSpec=} runtime the runtime being asked about
|
|
1134
1346
|
* @returns {boolean} true when a chunk of that runtime fetches its binaries
|
|
1135
1347
|
*/
|
|
1136
1348
|
_anyWasmChunkFetches(runtime) {
|
|
1137
|
-
const fetching = this.
|
|
1138
|
-
if (fetching ===
|
|
1349
|
+
const { fetching } = this._wasmGroups();
|
|
1350
|
+
if (fetching.size === 0) return false;
|
|
1139
1351
|
// Without a runtime to place it in there is nothing to narrow by, so any chunk
|
|
1140
1352
|
// answers for all of them.
|
|
1141
1353
|
if (runtime === undefined) return true;
|
|
1142
|
-
|
|
1143
|
-
if (typeof runtime === "string") {
|
|
1144
|
-
return fetching.has(this._wasmGroupOf(groups, runtime));
|
|
1145
|
-
}
|
|
1146
|
-
for (const key of runtime) {
|
|
1147
|
-
if (fetching.has(this._wasmGroupOf(groups, key))) return true;
|
|
1148
|
-
}
|
|
1149
|
-
return false;
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
/**
|
|
1153
|
-
* Whether every entry of a wasm runtime group reads its binaries with `fetch`. Only
|
|
1154
|
-
* an entry names a loader, so the scan is of entries, as `_wasmFetchingGroups` is.
|
|
1155
|
-
* @returns {Map<string, boolean>} whether each group fetches and nothing else
|
|
1156
|
-
*/
|
|
1157
|
-
_wasmGroupOnlyFetches() {
|
|
1158
|
-
if (this._wasmGroupOnlyFetchesMap === undefined) {
|
|
1159
|
-
const groups = this._wasmRuntimeGroups();
|
|
1160
|
-
/** @type {Map<string, boolean>} */
|
|
1161
|
-
const only = new Map();
|
|
1162
|
-
for (const chunk of this.compilation.chunks) {
|
|
1163
|
-
if (!chunk.getEntryOptions()) continue;
|
|
1164
|
-
const fetches = this._chunkWasmLoading(chunk) === "fetch";
|
|
1165
|
-
forEachRuntime(chunk.runtime, (key) => {
|
|
1166
|
-
const group = this._wasmGroupOf(groups, /** @type {string} */ (key));
|
|
1167
|
-
only.set(group, only.get(group) !== false && fetches);
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1170
|
-
this._wasmGroupOnlyFetchesMap = only;
|
|
1171
|
-
}
|
|
1172
|
-
return this._wasmGroupOnlyFetchesMap;
|
|
1354
|
+
return this._wasmGroupsOf(runtime).some((group) => fetching.has(group));
|
|
1173
1355
|
}
|
|
1174
1356
|
|
|
1175
1357
|
/**
|
|
@@ -1182,30 +1364,31 @@ class RuntimeTemplate {
|
|
|
1182
1364
|
_wasmFetchAnchorIsKnown(runtime) {
|
|
1183
1365
|
if (this._wasmAnchorKnownByGroup === undefined) {
|
|
1184
1366
|
const { chunkGraph, modules } = this.compilation;
|
|
1185
|
-
const
|
|
1186
|
-
this.outputOptions.publicPath
|
|
1187
|
-
);
|
|
1188
|
-
const groups = this._wasmRuntimeGroups();
|
|
1367
|
+
const { groupOf, onlyFetching } = this._wasmGroups();
|
|
1189
1368
|
/** @type {Map<string, boolean>} */
|
|
1190
1369
|
const known = new Map();
|
|
1191
1370
|
for (const module of modules) {
|
|
1192
1371
|
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1372
|
+
// Probed through the very builder the generator runs, so the gate is
|
|
1373
|
+
// exact: a prefix it can spell — the per-asset deferrals included — is
|
|
1374
|
+
// one the group may bake. The probe name stands in for the binary's.
|
|
1193
1375
|
const spellable =
|
|
1194
|
-
this.
|
|
1195
|
-
|
|
1376
|
+
this._getAnalyzableFileSpecifier(
|
|
1377
|
+
module,
|
|
1378
|
+
/** @type {ChunkGraph} */ (chunkGraph),
|
|
1379
|
+
[["literal", "x"]],
|
|
1380
|
+
true
|
|
1381
|
+
) !== null;
|
|
1196
1382
|
for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
|
|
1197
1383
|
forEachRuntime(moduleRuntime, (key) => {
|
|
1198
|
-
const group =
|
|
1199
|
-
groups,
|
|
1200
|
-
/** @type {string} */ (key)
|
|
1201
|
-
);
|
|
1384
|
+
const group = groupOf(/** @type {string} */ (key));
|
|
1202
1385
|
known.set(group, known.get(group) !== false && spellable);
|
|
1203
1386
|
});
|
|
1204
1387
|
}
|
|
1205
1388
|
}
|
|
1206
1389
|
// A group one entry reads with `readFile` cannot take a prefix meant for the
|
|
1207
1390
|
// document, and only an entry names its loader.
|
|
1208
|
-
for (const [group, only] of
|
|
1391
|
+
for (const [group, only] of onlyFetching) {
|
|
1209
1392
|
if (!only) known.set(group, false);
|
|
1210
1393
|
}
|
|
1211
1394
|
this._wasmAnchorKnownByGroup = known;
|
|
@@ -1217,124 +1400,9 @@ class RuntimeTemplate {
|
|
|
1217
1400
|
for (const value of known.values()) if (!value) return false;
|
|
1218
1401
|
return known.size > 0;
|
|
1219
1402
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}
|
|
1224
|
-
for (const key of runtime) {
|
|
1225
|
-
if (known.get(this._wasmGroupOf(groups, key)) !== true) return false;
|
|
1226
|
-
}
|
|
1227
|
-
return true;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
/**
|
|
1231
|
-
* The runtime groups an entry of which asked for the `fetch` loader, or `undefined`
|
|
1232
|
-
* where none did — the cheap answer for a compilation with no fetching entry at all,
|
|
1233
|
-
* which is every non-web target. Only an entry names a loader; every other chunk of
|
|
1234
|
-
* the runtime is served by the one its entry asked for.
|
|
1235
|
-
* @returns {Set<string> | undefined} the groups that fetch
|
|
1236
|
-
*/
|
|
1237
|
-
_wasmFetchingGroups() {
|
|
1238
|
-
if (this._wasmFetchingGroupSet === undefined) {
|
|
1239
|
-
/** @type {Set<string>} */
|
|
1240
|
-
const fetching = new Set();
|
|
1241
|
-
/** @type {Map<string, string> | undefined} */
|
|
1242
|
-
let groups;
|
|
1243
|
-
for (const chunk of this.compilation.chunks) {
|
|
1244
|
-
// Only an entry names a loader; every other chunk of the runtime is served
|
|
1245
|
-
// by the one its entry asked for, so it says nothing on its own.
|
|
1246
|
-
if (!chunk.getEntryOptions()) continue;
|
|
1247
|
-
if (this._chunkWasmLoading(chunk) !== "fetch") continue;
|
|
1248
|
-
// Built only once something fetches, so nothing pays for the grouping.
|
|
1249
|
-
if (groups === undefined) groups = this._wasmRuntimeGroups();
|
|
1250
|
-
const named = /** @type {Map<string, string>} */ (groups);
|
|
1251
|
-
forEachRuntime(chunk.runtime, (key) => {
|
|
1252
|
-
fetching.add(this._wasmGroupOf(named, /** @type {string} */ (key)));
|
|
1253
|
-
});
|
|
1254
|
-
}
|
|
1255
|
-
this._wasmFetchingGroupSet = fetching.size === 0 ? false : fetching;
|
|
1256
|
-
}
|
|
1257
|
-
return this._wasmFetchingGroupSet === false
|
|
1258
|
-
? undefined
|
|
1259
|
-
: this._wasmFetchingGroupSet;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
/**
|
|
1263
|
-
* Runtime keys mapped to the group they answer with, named by one key of it. Code
|
|
1264
|
-
* generation runs once for runtimes a module hashes alike in, and nothing in a
|
|
1265
|
-
* binary's hash knows which loader will read it — so a binary two runtimes reach
|
|
1266
|
-
* carries one shape into both, and a third runtime sharing another binary with
|
|
1267
|
-
* either is pulled in after them. A key in no group answers as itself. Asked of the
|
|
1268
|
-
* same modules the loaders are created for, and only once per compilation.
|
|
1269
|
-
* @returns {Map<string, string>} runtime key to the group it answers with
|
|
1270
|
-
*/
|
|
1271
|
-
_wasmRuntimeGroups() {
|
|
1272
|
-
if (this._wasmRuntimeGroupsByKey === undefined) {
|
|
1273
|
-
const { chunkGraph } = this.compilation;
|
|
1274
|
-
/** @type {Map<string, string>} */
|
|
1275
|
-
const parent = new Map();
|
|
1276
|
-
/**
|
|
1277
|
-
* @param {string} key runtime key
|
|
1278
|
-
* @returns {string} the key naming its group
|
|
1279
|
-
*/
|
|
1280
|
-
const find = (key) => {
|
|
1281
|
-
let root = key;
|
|
1282
|
-
let seen = parent.get(root);
|
|
1283
|
-
while (seen !== undefined && seen !== root) {
|
|
1284
|
-
root = seen;
|
|
1285
|
-
seen = parent.get(root);
|
|
1286
|
-
}
|
|
1287
|
-
// Path compression keeps a long share chain from costing more than once.
|
|
1288
|
-
let walk = key;
|
|
1289
|
-
let next = parent.get(walk);
|
|
1290
|
-
while (next !== undefined && next !== root) {
|
|
1291
|
-
parent.set(walk, root);
|
|
1292
|
-
walk = next;
|
|
1293
|
-
next = parent.get(walk);
|
|
1294
|
-
}
|
|
1295
|
-
return root;
|
|
1296
|
-
};
|
|
1297
|
-
/** @type {string[]} */
|
|
1298
|
-
const keys = [];
|
|
1299
|
-
/**
|
|
1300
|
-
* @param {RuntimeSpec} runtime a runtime the module is generated for
|
|
1301
|
-
* @returns {void}
|
|
1302
|
-
*/
|
|
1303
|
-
const collectKeys = (runtime) => {
|
|
1304
|
-
forEachRuntime(runtime, (key) => {
|
|
1305
|
-
keys.push(/** @type {string} */ (key));
|
|
1306
|
-
});
|
|
1307
|
-
};
|
|
1308
|
-
for (const module of this.compilation.modules) {
|
|
1309
|
-
if (module.type !== WEBASSEMBLY_MODULE_TYPE_ASYNC) continue;
|
|
1310
|
-
keys.length = 0;
|
|
1311
|
-
for (const runtime of chunkGraph.getModuleRuntimes(module)) {
|
|
1312
|
-
collectKeys(runtime);
|
|
1313
|
-
}
|
|
1314
|
-
for (const key of keys) {
|
|
1315
|
-
if (!parent.has(key)) parent.set(key, key);
|
|
1316
|
-
}
|
|
1317
|
-
// Every runtime this binary reaches answers with the first one.
|
|
1318
|
-
for (let i = 1; i < keys.length; i++) {
|
|
1319
|
-
parent.set(find(keys[i]), find(keys[0]));
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
// Flattened once, so a lookup is a single `get` rather than a chain walk.
|
|
1323
|
-
for (const key of parent.keys()) parent.set(key, find(key));
|
|
1324
|
-
this._wasmRuntimeGroupsByKey = parent;
|
|
1325
|
-
}
|
|
1326
|
-
return this._wasmRuntimeGroupsByKey;
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* @param {Map<string, string>} groups runtime key to the group it answers with
|
|
1331
|
-
* @param {string} key a runtime key
|
|
1332
|
-
* @returns {string} the group it answers with, or itself when it shares nothing
|
|
1333
|
-
*/
|
|
1334
|
-
_wasmGroupOf(groups, key) {
|
|
1335
|
-
const group = groups.get(key);
|
|
1336
|
-
// An entry named "" makes "" a runtime key, so test absence, not a falsy value.
|
|
1337
|
-
return group === undefined ? key : group;
|
|
1403
|
+
return this._wasmGroupsOf(runtime).every(
|
|
1404
|
+
(group) => known.get(group) === true
|
|
1405
|
+
);
|
|
1338
1406
|
}
|
|
1339
1407
|
|
|
1340
1408
|
supportTemplateLiteral() {
|
|
@@ -1413,14 +1481,13 @@ class RuntimeTemplate {
|
|
|
1413
1481
|
}
|
|
1414
1482
|
if (!this.supportTemplateLiteral()) return this._es5Concatenation(args);
|
|
1415
1483
|
|
|
1416
|
-
// cost comparison between template literal and concatenation
|
|
1417
|
-
//
|
|
1418
|
-
//
|
|
1419
|
-
//
|
|
1420
|
-
//
|
|
1421
|
-
//
|
|
1422
|
-
//
|
|
1423
|
-
// e. g. `x${a}x${b}x${c}x` (3*3 = 9) is shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12)
|
|
1484
|
+
// WHY: cost comparison between a template literal and a concatenation, both
|
|
1485
|
+
// needing equal surroundings (`xxx` against "xxx"). A template literal costs
|
|
1486
|
+
// a constant 3 chars per expression; an es5 concatenation costs 3 + n chars
|
|
1487
|
+
// for n expressions in a row, and reduces by 3 where it ends with an
|
|
1488
|
+
// expression or starts with a single one. So `${a}${b}${c}` (3*3 = 9) is
|
|
1489
|
+
// longer than ""+a+b+c ((3+3)-3 = 3), while `x${a}x${b}x${c}x` (3*3 = 9) is
|
|
1490
|
+
// shorter than "x"+a+"x"+b+"x"+c+"x" (4+4+4 = 12).
|
|
1424
1491
|
|
|
1425
1492
|
let templateCost = 0;
|
|
1426
1493
|
let concatenationCost = 0;
|
|
@@ -1897,14 +1964,21 @@ class RuntimeTemplate {
|
|
|
1897
1964
|
});
|
|
1898
1965
|
const exportsType = module.getExportsType(chunkGraph.moduleGraph, strict);
|
|
1899
1966
|
switch (exportsType) {
|
|
1900
|
-
case "namespace":
|
|
1901
|
-
|
|
1967
|
+
case "namespace": {
|
|
1968
|
+
const raw = this.moduleRaw({
|
|
1902
1969
|
module,
|
|
1903
1970
|
chunkGraph,
|
|
1904
1971
|
request,
|
|
1905
1972
|
weak,
|
|
1906
1973
|
runtimeRequirements
|
|
1907
1974
|
});
|
|
1975
|
+
|
|
1976
|
+
if (!usesSpecNamespaceObject(module)) return raw;
|
|
1977
|
+
|
|
1978
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
1979
|
+
|
|
1980
|
+
return `${RuntimeGlobals.specNamespaceObject}(${raw})`;
|
|
1981
|
+
}
|
|
1908
1982
|
case "default-with-named":
|
|
1909
1983
|
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
|
|
1910
1984
|
return `${RuntimeGlobals.createFakeNamespaceObject}(${moduleId}, 3)`;
|
|
@@ -2013,12 +2087,30 @@ class RuntimeTemplate {
|
|
|
2013
2087
|
|
|
2014
2088
|
let mode = getMakeDeferredNamespaceModeFromExportsType(exportsType);
|
|
2015
2089
|
if (mode) mode = `${mode} | 16`;
|
|
2090
|
+
// The spec's namespace keys are the sorted exports, so hand them over
|
|
2091
|
+
// when they are fully known; otherwise the runtime stays permissive.
|
|
2092
|
+
const deferredExportNames = getKnownExportNames(
|
|
2093
|
+
chunkGraph.moduleGraph,
|
|
2094
|
+
module,
|
|
2095
|
+
exportsType
|
|
2096
|
+
);
|
|
2097
|
+
runtimeRequirements.add(
|
|
2098
|
+
deferredExportNames
|
|
2099
|
+
? RuntimeGlobals.hasSealedDeferredNamespace
|
|
2100
|
+
: RuntimeGlobals.hasSynthesizedDeferredNamespace
|
|
2101
|
+
);
|
|
2102
|
+
mode += deferredExportNames
|
|
2103
|
+
? `, ${JSON.stringify(deferredExportNames)}`
|
|
2104
|
+
: "";
|
|
2016
2105
|
|
|
2017
2106
|
const asyncDeps = Array.from(
|
|
2018
2107
|
getOutgoingAsyncModules(chunkGraph.moduleGraph, module),
|
|
2019
2108
|
(m) => chunkGraph.getModuleId(m)
|
|
2020
2109
|
).filter((id) => id !== null);
|
|
2021
2110
|
if (asyncDeps.length) {
|
|
2111
|
+
runtimeRequirements.add(
|
|
2112
|
+
RuntimeGlobals.deferredModuleAsyncTransitiveDependencies
|
|
2113
|
+
);
|
|
2022
2114
|
if (header) {
|
|
2023
2115
|
appending = `.then(${this.basicFunction(
|
|
2024
2116
|
"",
|
|
@@ -2053,15 +2145,22 @@ class RuntimeTemplate {
|
|
|
2053
2145
|
} else {
|
|
2054
2146
|
let fakeType = 16;
|
|
2055
2147
|
switch (exportsType) {
|
|
2056
|
-
case "namespace":
|
|
2057
|
-
|
|
2058
|
-
|
|
2148
|
+
case "namespace": {
|
|
2149
|
+
const specNamespace = usesSpecNamespaceObject(module);
|
|
2150
|
+
const asyncModule = chunkGraph.moduleGraph.isAsync(module);
|
|
2151
|
+
if (header || (specNamespace && !asyncModule)) {
|
|
2152
|
+
let rawModule = this.moduleRaw({
|
|
2059
2153
|
module,
|
|
2060
2154
|
chunkGraph,
|
|
2061
2155
|
request,
|
|
2062
2156
|
weak,
|
|
2063
2157
|
runtimeRequirements
|
|
2064
2158
|
});
|
|
2159
|
+
if (specNamespace && !asyncModule) {
|
|
2160
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2161
|
+
// Wrap before promise resolution assimilates an exported `then`.
|
|
2162
|
+
rawModule = `${RuntimeGlobals.specNamespaceObject}(${rawModule})`;
|
|
2163
|
+
}
|
|
2065
2164
|
appending = `.then(${this.basicFunction(
|
|
2066
2165
|
"",
|
|
2067
2166
|
`${header}return ${rawModule};`
|
|
@@ -2073,7 +2172,14 @@ class RuntimeTemplate {
|
|
|
2073
2172
|
`${comment}${idExpr}`
|
|
2074
2173
|
)})`;
|
|
2075
2174
|
}
|
|
2175
|
+
|
|
2176
|
+
if (specNamespace && asyncModule) {
|
|
2177
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2178
|
+
appending += `.then(${RuntimeGlobals.specNamespaceObject})`;
|
|
2179
|
+
}
|
|
2180
|
+
|
|
2076
2181
|
break;
|
|
2182
|
+
}
|
|
2077
2183
|
case "dynamic":
|
|
2078
2184
|
fakeType |= 4;
|
|
2079
2185
|
/* fall through */
|
|
@@ -2127,6 +2233,15 @@ class RuntimeTemplate {
|
|
|
2127
2233
|
)})`;
|
|
2128
2234
|
}
|
|
2129
2235
|
}
|
|
2236
|
+
if (synthesizesSpecNamespaceObject(originModule)) {
|
|
2237
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2238
|
+
runtimeRequirements.add(RuntimeGlobals.moduleCache);
|
|
2239
|
+
const owner = synthesizedNamespaceOwner(moduleId, fakeType);
|
|
2240
|
+
appending += `.then(${this.returningFunction(
|
|
2241
|
+
`${RuntimeGlobals.specNamespaceObject}(m${owner})`,
|
|
2242
|
+
"m"
|
|
2243
|
+
)})`;
|
|
2244
|
+
}
|
|
2130
2245
|
break;
|
|
2131
2246
|
}
|
|
2132
2247
|
}
|
|
@@ -2235,10 +2350,9 @@ class RuntimeTemplate {
|
|
|
2235
2350
|
request,
|
|
2236
2351
|
weak
|
|
2237
2352
|
});
|
|
2238
|
-
//
|
|
2239
|
-
//
|
|
2240
|
-
//
|
|
2241
|
-
// block-scoped (`let`/`const`).
|
|
2353
|
+
// A harmony import may sit inside a runtime-condition `if` block yet be
|
|
2354
|
+
// referenced outside it, so it stays function-scoped with `var` rather than
|
|
2355
|
+
// block-scoped.
|
|
2242
2356
|
const optDeclaration = update ? "" : "var ";
|
|
2243
2357
|
|
|
2244
2358
|
const exportsType = module.getExportsType(
|
|
@@ -2255,11 +2369,14 @@ class RuntimeTemplate {
|
|
|
2255
2369
|
(dependency instanceof HarmonyImportDependency ||
|
|
2256
2370
|
dependency instanceof ImportDependency) &&
|
|
2257
2371
|
ImportPhaseUtils.isDefer(dependency.phase) &&
|
|
2258
|
-
!(
|
|
2372
|
+
!isAsyncExternal(module);
|
|
2259
2373
|
|
|
2260
2374
|
if (isModuleDeferred) {
|
|
2261
2375
|
/** @type {Set<Module>} */
|
|
2262
2376
|
const outgoingAsyncModules = getOutgoingAsyncModules(moduleGraph, module);
|
|
2377
|
+
// A module deferring itself is already evaluating, so awaiting it here
|
|
2378
|
+
// would deadlock; forcing the namespace throws instead.
|
|
2379
|
+
outgoingAsyncModules.delete(originModule);
|
|
2263
2380
|
|
|
2264
2381
|
importContent = `/* deferred harmony import */ ${optDeclaration}${importVar} = ${getOptimizedDeferredModule(
|
|
2265
2382
|
moduleId,
|
|
@@ -2344,7 +2461,7 @@ class RuntimeTemplate {
|
|
|
2344
2461
|
(dependency instanceof HarmonyImportDependency ||
|
|
2345
2462
|
dependency instanceof ImportDependency) &&
|
|
2346
2463
|
ImportPhaseUtils.isDefer(dependency.phase) &&
|
|
2347
|
-
!(
|
|
2464
|
+
!isAsyncExternal(module);
|
|
2348
2465
|
|
|
2349
2466
|
if (defaultInterop) {
|
|
2350
2467
|
// when the defaultInterop is used (when a ESM imports a CJS module),
|
|
@@ -2374,10 +2491,8 @@ class RuntimeTemplate {
|
|
|
2374
2491
|
}
|
|
2375
2492
|
// accessing the .default property is same thing as `require()` the module.
|
|
2376
2493
|
|
|
2377
|
-
//
|
|
2378
|
-
//
|
|
2379
|
-
// is translated to
|
|
2380
|
-
// var mod = require("cjs"); mod.x;
|
|
2494
|
+
// So `import mod from "cjs"; mod.default.x` translates to
|
|
2495
|
+
// `var mod = require("cjs"); mod.x`.
|
|
2381
2496
|
switch (exportsType) {
|
|
2382
2497
|
case "dynamic":
|
|
2383
2498
|
if (isCall) {
|
|
@@ -2417,10 +2532,9 @@ class RuntimeTemplate {
|
|
|
2417
2532
|
exportsType === "default-only" ||
|
|
2418
2533
|
exportsType === "default-with-named"
|
|
2419
2534
|
) {
|
|
2420
|
-
//
|
|
2421
|
-
//
|
|
2422
|
-
//
|
|
2423
|
-
// we will need to createFakeNamespaceObject that simulates ES Module namespace object
|
|
2535
|
+
// `exportName.length` is 0, so the namespace object is used in an unknown
|
|
2536
|
+
// way — `import * as ns from "cjs"; console.log(ns)` — and needs
|
|
2537
|
+
// `createFakeNamespaceObject` to simulate an ES module namespace.
|
|
2424
2538
|
runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
|
|
2425
2539
|
initFragments.push(
|
|
2426
2540
|
new InitFragment(
|
|
@@ -2430,16 +2544,38 @@ class RuntimeTemplate {
|
|
|
2430
2544
|
`${importVar}_namespace_cache`
|
|
2431
2545
|
)
|
|
2432
2546
|
);
|
|
2547
|
+
const fakeMode = exportsType === "default-only" ? 0 : 2;
|
|
2548
|
+
const fakeArguments = fakeMode === 0 ? "" : ", 2";
|
|
2549
|
+
let fakeNamespace = `${RuntimeGlobals.createFakeNamespaceObject}(${importVar}${fakeArguments})`;
|
|
2550
|
+
if (synthesizesSpecNamespaceObject(originModule)) {
|
|
2551
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2552
|
+
runtimeRequirements.add(RuntimeGlobals.moduleCache);
|
|
2553
|
+
const owner = synthesizedNamespaceOwner(
|
|
2554
|
+
chunkGraph.getModuleId(module),
|
|
2555
|
+
fakeMode
|
|
2556
|
+
);
|
|
2557
|
+
fakeNamespace = `${RuntimeGlobals.specNamespaceObject}(${fakeNamespace}${owner})`;
|
|
2558
|
+
}
|
|
2433
2559
|
return `/*#__PURE__*/ ${
|
|
2434
2560
|
asiSafe ? "" : asiSafe === false ? ";" : "Object"
|
|
2435
|
-
}(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${
|
|
2436
|
-
RuntimeGlobals.createFakeNamespaceObject
|
|
2437
|
-
}(${importVar}${exportsType === "default-only" ? "" : ", 2"})))`;
|
|
2561
|
+
}(${importVar}_namespace_cache || (${importVar}_namespace_cache = ${fakeNamespace}))`;
|
|
2438
2562
|
}
|
|
2439
2563
|
}
|
|
2440
2564
|
|
|
2441
2565
|
if (exportName.length > 0) {
|
|
2442
2566
|
const exportsInfo = moduleGraph.getExportsInfo(module);
|
|
2567
|
+
// A name the module does not export is the namespace's to answer — reading
|
|
2568
|
+
// it is undefined and writing it fails — not the exports object's.
|
|
2569
|
+
if (
|
|
2570
|
+
!isModuleDeferred &&
|
|
2571
|
+
usesSpecNamespaceObject(module) &&
|
|
2572
|
+
exportsInfo.isExportProvided(exportName) === false
|
|
2573
|
+
) {
|
|
2574
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2575
|
+
const ns = `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
|
|
2576
|
+
|
|
2577
|
+
return `${ns}${propertyAccess(exportName)}`;
|
|
2578
|
+
}
|
|
2443
2579
|
// in some case the exported item is renamed (get this by getUsedName). for example,
|
|
2444
2580
|
// x.default might be emitted as x.Z (default is renamed to Z)
|
|
2445
2581
|
const used = exportsInfo.getUsedName(exportName, runtime);
|
|
@@ -2484,9 +2620,19 @@ class RuntimeTemplate {
|
|
|
2484
2620
|
runtimeRequirements.add(RuntimeGlobals.makeDeferredNamespaceObject);
|
|
2485
2621
|
const id = chunkGraph.getModuleId(module);
|
|
2486
2622
|
const type = getMakeDeferredNamespaceModeFromExportsType(exportsType);
|
|
2487
|
-
const
|
|
2488
|
-
|
|
2489
|
-
|
|
2623
|
+
const names = getKnownExportNames(
|
|
2624
|
+
chunkGraph.moduleGraph,
|
|
2625
|
+
module,
|
|
2626
|
+
exportsType
|
|
2627
|
+
);
|
|
2628
|
+
runtimeRequirements.add(
|
|
2629
|
+
names
|
|
2630
|
+
? RuntimeGlobals.hasSealedDeferredNamespace
|
|
2631
|
+
: RuntimeGlobals.hasSynthesizedDeferredNamespace
|
|
2632
|
+
);
|
|
2633
|
+
const init = `${RuntimeGlobals.makeDeferredNamespaceObject}(${JSON.stringify(
|
|
2634
|
+
id
|
|
2635
|
+
)}, ${type}${names ? `, ${JSON.stringify(names)}` : ""})`;
|
|
2490
2636
|
|
|
2491
2637
|
return `/*#__PURE__*/ ${
|
|
2492
2638
|
asiSafe ? "" : asiSafe === false ? ";" : "Object"
|
|
@@ -2513,6 +2659,16 @@ class RuntimeTemplate {
|
|
|
2513
2659
|
// if we hit here, the importVar is either
|
|
2514
2660
|
// - already a ES module namespace object
|
|
2515
2661
|
// - or imported by a way that does not need interop.
|
|
2662
|
+
if (
|
|
2663
|
+
exportsType === "namespace" &&
|
|
2664
|
+
exportName.length === 0 &&
|
|
2665
|
+
usesSpecNamespaceObject(module)
|
|
2666
|
+
) {
|
|
2667
|
+
runtimeRequirements.add(RuntimeGlobals.specNamespaceObject);
|
|
2668
|
+
|
|
2669
|
+
return `${RuntimeGlobals.specNamespaceObject}(${importVar})`;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2516
2672
|
return importVar;
|
|
2517
2673
|
}
|
|
2518
2674
|
|
|
@@ -2593,7 +2749,7 @@ class RuntimeTemplate {
|
|
|
2593
2749
|
* @param {string} options.message the message
|
|
2594
2750
|
* @param {ChunkGraph} options.chunkGraph the chunk graph
|
|
2595
2751
|
* @param {RuntimeRequirements} options.runtimeRequirements if set, will be filled with runtime requirements
|
|
2596
|
-
* @param {Module=} options.originModule the module the `import()` is emitted into
|
|
2752
|
+
* @param {Module=} options.originModule the module the `import()` is emitted into, to report against
|
|
2597
2753
|
* @returns {string} expression
|
|
2598
2754
|
*/
|
|
2599
2755
|
blockPromise({
|
|
@@ -2607,165 +2763,48 @@ class RuntimeTemplate {
|
|
|
2607
2763
|
const comment = this.comment({
|
|
2608
2764
|
message
|
|
2609
2765
|
});
|
|
2610
|
-
return `Promise.resolve(${comment.trim()})`;
|
|
2611
|
-
}
|
|
2612
|
-
const chunkGroup = chunkGraph.getBlockChunkGroup(block);
|
|
2613
|
-
if (!chunkGroup || chunkGroup.chunks.length === 0) {
|
|
2614
|
-
const comment = this.comment({
|
|
2615
|
-
message
|
|
2616
|
-
});
|
|
2617
|
-
return `Promise.resolve(${comment.trim()})`;
|
|
2618
|
-
}
|
|
2619
|
-
const chunks = chunkGroup.chunks.filter(
|
|
2620
|
-
(chunk) => !chunk.hasRuntime() && chunk.id !== null
|
|
2621
|
-
);
|
|
2622
|
-
const comment = this.comment({
|
|
2623
|
-
message,
|
|
2624
|
-
chunkName: block.chunkName
|
|
2625
|
-
});
|
|
2626
|
-
// `fetchPriority` is unsupported for ESM output (a native `import()` can't carry it,
|
|
2627
|
-
// and the ESM chunk loader ignores the argument), so it never blocks the analyzable form.
|
|
2628
|
-
// TODO recheck: browsers honor `fetchpriority` on `modulepreload` only when the
|
|
2629
|
-
// preload scanner sees it, so a runtime-injected hint is inert; support it here if
|
|
2630
|
-
// that changes.
|
|
2631
|
-
const fetchPriority = chunkGroup.options.fetchPriority;
|
|
2632
|
-
if (chunks.length === 1) {
|
|
2633
|
-
const analyzable = this.analyzableChunkImport(
|
|
2634
|
-
chunks[0],
|
|
2635
|
-
comment,
|
|
2636
|
-
runtimeRequirements,
|
|
2637
|
-
originModule,
|
|
2638
|
-
chunkGraph
|
|
2639
|
-
);
|
|
2640
|
-
if (analyzable !== null) {
|
|
2641
|
-
return analyzable;
|
|
2642
|
-
}
|
|
2643
|
-
const chunkId = JSON.stringify(chunks[0].id);
|
|
2644
|
-
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
|
|
2645
|
-
|
|
2646
|
-
if (fetchPriority) {
|
|
2647
|
-
runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
|
|
2648
|
-
}
|
|
2649
|
-
|
|
2650
|
-
return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${
|
|
2651
|
-
fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
|
|
2652
|
-
})`;
|
|
2653
|
-
} else if (chunks.length > 0) {
|
|
2654
|
-
let needEnsureChunk = false;
|
|
2655
|
-
/**
|
|
2656
|
-
* Analyzable `import()` for a solely-owned JS chunk, else runtime ensureChunk.
|
|
2657
|
-
* @param {Chunk} chunk chunk
|
|
2658
|
-
* @returns {string} require chunk id code
|
|
2659
|
-
*/
|
|
2660
|
-
const requireChunkId = (chunk) => {
|
|
2661
|
-
const analyzable = this.analyzableChunkImport(
|
|
2662
|
-
chunk,
|
|
2663
|
-
"",
|
|
2664
|
-
runtimeRequirements,
|
|
2665
|
-
originModule,
|
|
2666
|
-
chunkGraph
|
|
2667
|
-
);
|
|
2668
|
-
if (analyzable !== null) return analyzable;
|
|
2669
|
-
needEnsureChunk = true;
|
|
2670
|
-
return `${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${
|
|
2671
|
-
fetchPriority ? `, ${JSON.stringify(fetchPriority)}` : ""
|
|
2672
|
-
})`;
|
|
2673
|
-
};
|
|
2674
|
-
const items = chunks.map(requireChunkId);
|
|
2675
|
-
if (needEnsureChunk) {
|
|
2676
|
-
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
|
|
2677
|
-
// Only needed when an `ensureChunk(id, priority)` call is actually emitted.
|
|
2678
|
-
if (fetchPriority) {
|
|
2679
|
-
runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
|
|
2680
|
-
}
|
|
2681
|
-
}
|
|
2682
|
-
return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
|
|
2683
|
-
}
|
|
2684
|
-
return `Promise.resolve(${comment.trim()})`;
|
|
2685
|
-
}
|
|
2686
|
-
|
|
2687
|
-
/**
|
|
2688
|
-
* For ESM module output, load a single statically-named chunk through the
|
|
2689
|
-
* `analyzableChunkImport` helper — a literal `import("./chunk.js")` other bundlers
|
|
2690
|
-
* and webpack itself can follow, wrapped to keep `ensureChunk` timing and deduplication.
|
|
2691
|
-
* Returns `null` to fall back to the runtime `ensureChunk` form.
|
|
2692
|
-
* @param {Chunk} chunk the chunk to load
|
|
2693
|
-
* @param {string} comment leading comment (chunk name / message)
|
|
2694
|
-
* @param {RuntimeRequirements} runtimeRequirements runtime requirements
|
|
2695
|
-
* @param {Module | undefined} originModule the module the `import()` is emitted into
|
|
2696
|
-
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
2697
|
-
* @returns {string | null} the import expression, or `null`
|
|
2698
|
-
*/
|
|
2699
|
-
analyzableChunkImport(
|
|
2700
|
-
chunk,
|
|
2701
|
-
comment,
|
|
2702
|
-
runtimeRequirements,
|
|
2703
|
-
originModule,
|
|
2704
|
-
chunkGraph
|
|
2705
|
-
) {
|
|
2706
|
-
// `blockPromise` has already dropped any chunk without an id. Without an origin
|
|
2707
|
-
// there is nothing the specifier could be relative to.
|
|
2708
|
-
if (
|
|
2709
|
-
!originModule ||
|
|
2710
|
-
!this.supportsAnalyzable("import", chunkGraph, originModule)
|
|
2711
|
-
) {
|
|
2712
|
-
return null;
|
|
2766
|
+
return `Promise.resolve(${comment.trim()})`;
|
|
2713
2767
|
}
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
// `.ei` always performs the import, where `.e` only reaches the javascript
|
|
2721
|
-
// loader when there is javascript to load. A module federation remote is the
|
|
2722
|
-
// case that matters: its chunk is emitted by the container's build, not this one.
|
|
2723
|
-
if (!JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) {
|
|
2724
|
-
this._analyzableBailout(
|
|
2725
|
-
originModule,
|
|
2726
|
-
"this compilation emits no javascript for the chunk, so there is nothing to import"
|
|
2727
|
-
);
|
|
2728
|
-
return null;
|
|
2768
|
+
const chunkGroup = chunkGraph.getBlockChunkGroup(block);
|
|
2769
|
+
if (!chunkGroup || chunkGroup.chunks.length === 0) {
|
|
2770
|
+
const comment = this.comment({
|
|
2771
|
+
message
|
|
2772
|
+
});
|
|
2773
|
+
return `Promise.resolve(${comment.trim()})`;
|
|
2729
2774
|
}
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2775
|
+
const chunks = chunkGroup.chunks.filter(
|
|
2776
|
+
(chunk) => !chunk.hasRuntime() && chunk.id !== null
|
|
2777
|
+
);
|
|
2778
|
+
const comment = this.comment({
|
|
2779
|
+
message,
|
|
2780
|
+
chunkName: block.chunkName
|
|
2781
|
+
});
|
|
2782
|
+
// An output that cannot use a native `import()` gets no ESM chunk loader to ask,
|
|
2783
|
+
// so the reason is recorded here, where any build generates its imports.
|
|
2784
|
+
if (this.outputOptions.module && originModule !== undefined) {
|
|
2785
|
+
const outputReason = this._chunkImportOutputReason();
|
|
2786
|
+
if (outputReason !== null) {
|
|
2787
|
+
this._analyzableBailout(originModule, outputReason, false);
|
|
2737
2788
|
}
|
|
2738
2789
|
}
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
if (specifier === null) {
|
|
2748
|
-
return null;
|
|
2790
|
+
const fetchPriority = chunkGroup.options.fetchPriority;
|
|
2791
|
+
const priorityArg = fetchPriority
|
|
2792
|
+
? `, ${JSON.stringify(fetchPriority)}`
|
|
2793
|
+
: "";
|
|
2794
|
+
if (chunks.length === 0) return `Promise.resolve(${comment.trim()})`;
|
|
2795
|
+
runtimeRequirements.add(RuntimeGlobals.ensureChunk);
|
|
2796
|
+
if (fetchPriority) {
|
|
2797
|
+
runtimeRequirements.add(RuntimeGlobals.hasFetchPriority);
|
|
2749
2798
|
}
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
const resolvableSpecifier = /^"(?:\.{0,2}\/|[a-zA-Z][\w+.-]*:)/.test(
|
|
2754
|
-
specifier
|
|
2755
|
-
)
|
|
2756
|
-
? specifier
|
|
2757
|
-
: `"./${specifier.slice(1)}`;
|
|
2758
|
-
runtimeRequirements.add(RuntimeGlobals.analyzableChunkImport);
|
|
2759
|
-
if (needsHintHandlers || hasNonJsTypes) {
|
|
2760
|
-
// Those handlers attach to the `.f` map, which has to exist — but the runtime
|
|
2761
|
-
// `ensureChunk` around it does not, since `.ei` dispatches them itself.
|
|
2762
|
-
runtimeRequirements.add(RuntimeGlobals.ensureChunkHandlers);
|
|
2799
|
+
if (chunks.length === 1) {
|
|
2800
|
+
const chunkId = JSON.stringify(chunks[0].id);
|
|
2801
|
+
return `${RuntimeGlobals.ensureChunk}(${comment}${chunkId}${priorityArg})`;
|
|
2763
2802
|
}
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2803
|
+
const items = chunks.map(
|
|
2804
|
+
(chunk) =>
|
|
2805
|
+
`${RuntimeGlobals.ensureChunk}(${JSON.stringify(chunk.id)}${priorityArg})`
|
|
2806
|
+
);
|
|
2807
|
+
return `Promise.all(${comment.trim()}[${items.join(", ")}])`;
|
|
2769
2808
|
}
|
|
2770
2809
|
|
|
2771
2810
|
/**
|
|
@@ -2801,6 +2840,17 @@ class RuntimeTemplate {
|
|
|
2801
2840
|
const late = this._settlesLate(chunk);
|
|
2802
2841
|
if (late !== this._settlesLate(target)) return !late;
|
|
2803
2842
|
}
|
|
2843
|
+
return this._hashRoundBefore(chunk, target);
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
/**
|
|
2847
|
+
* Whether the four rounds alone settle `chunk` before `target`, leaving out what the
|
|
2848
|
+
* full-hash marks move: the order a runtime module generated in its chunk's round sees.
|
|
2849
|
+
* @param {Chunk} chunk the chunk whose hash would be read
|
|
2850
|
+
* @param {Chunk} target the chunk reading it
|
|
2851
|
+
* @returns {boolean} true when the hash exists by the time the target is hashed
|
|
2852
|
+
*/
|
|
2853
|
+
_hashRoundBefore(chunk, target) {
|
|
2804
2854
|
const chunkGraph = /** @type {ChunkGraph} */ (this.compilation.chunkGraph);
|
|
2805
2855
|
const round = hashRound(chunk, chunkGraph);
|
|
2806
2856
|
const targetRound = hashRound(target, chunkGraph);
|
|
@@ -2823,6 +2873,42 @@ class RuntimeTemplate {
|
|
|
2823
2873
|
);
|
|
2824
2874
|
}
|
|
2825
2875
|
|
|
2876
|
+
/**
|
|
2877
|
+
* Whether a `[chunkhash]`/`[contenthash]` name is settled before every chunk it is
|
|
2878
|
+
* written into, so a runtime module generated in its chunk's round can spell it.
|
|
2879
|
+
* @param {Chunk} chunk the chunk named
|
|
2880
|
+
* @param {string} template what names it
|
|
2881
|
+
* @param {Iterable<Chunk>} targets the chunks the name is written into
|
|
2882
|
+
* @returns {boolean} true when the hashes it reads exist by then
|
|
2883
|
+
*/
|
|
2884
|
+
_hashedNameSettledBefore(chunk, template, targets) {
|
|
2885
|
+
const kinds = getTemplatedPathPlugin().getPresentKinds(template);
|
|
2886
|
+
// The compilation hash exists in no round a chunk is hashed in.
|
|
2887
|
+
if (kinds.has("fullhash") || kinds.has("hash")) return false;
|
|
2888
|
+
for (const target of targets) {
|
|
2889
|
+
if (!this._hashRoundBefore(chunk, target)) return false;
|
|
2890
|
+
}
|
|
2891
|
+
return true;
|
|
2892
|
+
}
|
|
2893
|
+
|
|
2894
|
+
/**
|
|
2895
|
+
* Whether the hashes a name reads are on the chunk now, which they are only once its
|
|
2896
|
+
* round of `createHash` has run — never while modules are being generated.
|
|
2897
|
+
* @param {Chunk} chunk the chunk named
|
|
2898
|
+
* @param {string} template what names it
|
|
2899
|
+
* @param {string} sourceType which asset of the chunk it names
|
|
2900
|
+
* @returns {boolean} true when the name can be resolved here
|
|
2901
|
+
*/
|
|
2902
|
+
_hashedNamePresent(chunk, template, sourceType) {
|
|
2903
|
+
const kinds = getTemplatedPathPlugin().getPresentKinds(template);
|
|
2904
|
+
return (
|
|
2905
|
+
!kinds.has("fullhash") &&
|
|
2906
|
+
!kinds.has("hash") &&
|
|
2907
|
+
(!kinds.has("chunkhash") || chunk.hash !== undefined) &&
|
|
2908
|
+
(!kinds.has("contenthash") || chunk.contentHash[sourceType] !== undefined)
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2826
2912
|
/**
|
|
2827
2913
|
* Whether `createHash` settles this chunk's hash in the round that runs after the
|
|
2828
2914
|
* compilation hash rather than in one of the four before it. Asked of the chunk
|
|
@@ -2928,6 +3014,11 @@ class RuntimeTemplate {
|
|
|
2928
3014
|
/** @type {Set<string>} */
|
|
2929
3015
|
const names = new Set();
|
|
2930
3016
|
let found = false;
|
|
3017
|
+
// Its own copy, since `lastIndex` is walked below; reset by the loop that ends it.
|
|
3018
|
+
const regexp = new RegExp(
|
|
3019
|
+
ANALYZABLE_TOKEN_REGEXP.source,
|
|
3020
|
+
ANALYZABLE_TOKEN_REGEXP.flags
|
|
3021
|
+
);
|
|
2931
3022
|
for (const module of modules) {
|
|
2932
3023
|
if (!results.has(module, chunk.runtime)) continue;
|
|
2933
3024
|
const source = results.getSource(module, chunk.runtime, JAVASCRIPT_TYPE);
|
|
@@ -2937,10 +3028,6 @@ class RuntimeTemplate {
|
|
|
2937
3028
|
carriesFullHash = true;
|
|
2938
3029
|
found = true;
|
|
2939
3030
|
}
|
|
2940
|
-
const regexp = new RegExp(
|
|
2941
|
-
ANALYZABLE_TOKEN_REGEXP.source,
|
|
2942
|
-
ANALYZABLE_TOKEN_REGEXP.flags
|
|
2943
|
-
);
|
|
2944
3031
|
/** @type {RegExpExecArray | null} */
|
|
2945
3032
|
let match;
|
|
2946
3033
|
while ((match = regexp.exec(content)) !== null) {
|
|
@@ -2948,11 +3035,7 @@ class RuntimeTemplate {
|
|
|
2948
3035
|
if (parts === null) continue;
|
|
2949
3036
|
found = true;
|
|
2950
3037
|
for (const [kind, value] of parts) {
|
|
2951
|
-
if (
|
|
2952
|
-
kind === "publicPath" ||
|
|
2953
|
-
kind === "template" ||
|
|
2954
|
-
kind === "unserved"
|
|
2955
|
-
) {
|
|
3038
|
+
if (FULL_HASH_PART_KINDS.has(kind)) {
|
|
2956
3039
|
carriesFullHash = true;
|
|
2957
3040
|
} else if (CHUNK_SPECIFIER_PART_KINDS.has(kind)) {
|
|
2958
3041
|
names.add(String(value));
|
|
@@ -3087,35 +3170,6 @@ class RuntimeTemplate {
|
|
|
3087
3170
|
this._chunksByIdForFold = undefined;
|
|
3088
3171
|
}
|
|
3089
3172
|
|
|
3090
|
-
/**
|
|
3091
|
-
* Whether `chunk` can reach any of `targets` by following chunk groups, which is
|
|
3092
|
-
* what turns a baked hashed name into a hash that depends on itself.
|
|
3093
|
-
* @param {Chunk} chunk the referenced chunk
|
|
3094
|
-
* @param {Iterable<Chunk>} targets the chunks the reference is written into
|
|
3095
|
-
* @returns {boolean} true when one of them is reachable from `chunk`
|
|
3096
|
-
*/
|
|
3097
|
-
_reachesAny(chunk, targets) {
|
|
3098
|
-
const wanted = new Set(targets);
|
|
3099
|
-
if (wanted.size === 0) return false;
|
|
3100
|
-
if (wanted.has(chunk)) return true;
|
|
3101
|
-
/** @type {Set<ChunkGroup>} */
|
|
3102
|
-
const seen = new Set();
|
|
3103
|
-
/** @type {ChunkGroup[]} */
|
|
3104
|
-
const queue = [...chunk.groupsIterable];
|
|
3105
|
-
for (const group of queue) seen.add(group);
|
|
3106
|
-
for (let i = 0; i < queue.length; i++) {
|
|
3107
|
-
for (const child of queue[i].childrenIterable) {
|
|
3108
|
-
if (seen.has(child)) continue;
|
|
3109
|
-
seen.add(child);
|
|
3110
|
-
for (const candidate of child.chunks) {
|
|
3111
|
-
if (wanted.has(candidate)) return true;
|
|
3112
|
-
}
|
|
3113
|
-
queue.push(child);
|
|
3114
|
-
}
|
|
3115
|
-
}
|
|
3116
|
-
return false;
|
|
3117
|
-
}
|
|
3118
|
-
|
|
3119
3173
|
/**
|
|
3120
3174
|
* The chunks a reference emitted into `module` is written into — the assets a
|
|
3121
3175
|
* stand-in of ours would land in, and so the only ones a deferred fill could go
|
|
@@ -3213,13 +3267,13 @@ class RuntimeTemplate {
|
|
|
3213
3267
|
return template.replace(HASH_IN_FILENAME_GLOBAL, "x");
|
|
3214
3268
|
}
|
|
3215
3269
|
try {
|
|
3216
|
-
return
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3270
|
+
return probeTemplateName(
|
|
3271
|
+
template,
|
|
3272
|
+
chunk,
|
|
3273
|
+
JAVASCRIPT_TYPE,
|
|
3274
|
+
HASH_PROBE,
|
|
3275
|
+
true
|
|
3276
|
+
).replace(HASH_IN_FILENAME_GLOBAL, "x");
|
|
3223
3277
|
} catch (_error) {
|
|
3224
3278
|
// Nothing to report: the naming call is given strictly less than this probe, so
|
|
3225
3279
|
// one that throws here fails the build where the name is actually needed.
|
|
@@ -3231,7 +3285,7 @@ class RuntimeTemplate {
|
|
|
3231
3285
|
* The `../` path from a chunk's own asset back to the output root. Hashes are
|
|
3232
3286
|
* neutralized first: a runtime module is generated once to be hashed, before any
|
|
3233
3287
|
* hash exists, so resolving one there throws — and `RuntimeModule.updateHash`
|
|
3234
|
-
*
|
|
3288
|
+
* lets that throw fail the build rather than hashing it.
|
|
3235
3289
|
* @param {Chunk} chunk the chunk whose asset holds the reference
|
|
3236
3290
|
* @param {boolean} enforceRelative whether the answer keeps a leading `./`
|
|
3237
3291
|
* @returns {string} the path back to the output root
|
|
@@ -3262,7 +3316,10 @@ class RuntimeTemplate {
|
|
|
3262
3316
|
* @returns {Placement} where a literal in it is read from
|
|
3263
3317
|
*/
|
|
3264
3318
|
_modulePlacement(module, chunkGraph) {
|
|
3265
|
-
return this._placementOf(
|
|
3319
|
+
return this._placementOf(
|
|
3320
|
+
this._moduleChunks(module, chunkGraph),
|
|
3321
|
+
isHotModule(module)
|
|
3322
|
+
);
|
|
3266
3323
|
}
|
|
3267
3324
|
|
|
3268
3325
|
/**
|
|
@@ -3281,11 +3338,12 @@ class RuntimeTemplate {
|
|
|
3281
3338
|
|
|
3282
3339
|
/**
|
|
3283
3340
|
* The one answer every chunk in `chunks` agrees on, with either half `null` where
|
|
3284
|
-
* they do not.
|
|
3341
|
+
* they do not — under HMR the update chunk, which re-runs the module, has a say too.
|
|
3285
3342
|
* @param {Iterable<Chunk>} chunks the chunks a literal is written into
|
|
3343
|
+
* @param {boolean=} hot whether a hot update can re-run what is written
|
|
3286
3344
|
* @returns {Placement} where a literal in them is read from
|
|
3287
3345
|
*/
|
|
3288
|
-
_placementOf(chunks) {
|
|
3346
|
+
_placementOf(chunks, hot = false) {
|
|
3289
3347
|
/** @type {Placement | undefined} */
|
|
3290
3348
|
let first;
|
|
3291
3349
|
/** @type {string | null} */
|
|
@@ -3294,13 +3352,17 @@ class RuntimeTemplate {
|
|
|
3294
3352
|
let loaded = null;
|
|
3295
3353
|
for (const chunk of chunks) {
|
|
3296
3354
|
const own = this._chunkPlacement(chunk);
|
|
3355
|
+
const ownUndo =
|
|
3356
|
+
hot && own.undo !== null && own.undo !== this._hotUpdateUndo(chunk)
|
|
3357
|
+
? null
|
|
3358
|
+
: own.undo;
|
|
3297
3359
|
if (first === undefined) {
|
|
3298
3360
|
first = own;
|
|
3299
|
-
undo =
|
|
3361
|
+
undo = ownUndo;
|
|
3300
3362
|
loaded = own.loaded;
|
|
3301
3363
|
continue;
|
|
3302
3364
|
}
|
|
3303
|
-
if (undo !==
|
|
3365
|
+
if (undo !== ownUndo) undo = null;
|
|
3304
3366
|
if (loaded !== own.loaded) loaded = null;
|
|
3305
3367
|
}
|
|
3306
3368
|
if (first === undefined) return NO_PLACEMENT;
|
|
@@ -3311,6 +3373,33 @@ class RuntimeTemplate {
|
|
|
3311
3373
|
: { undo, loaded };
|
|
3312
3374
|
}
|
|
3313
3375
|
|
|
3376
|
+
/**
|
|
3377
|
+
* Static literal specifier (already quoted) for the `new URL(<here>, import.meta.url)`
|
|
3378
|
+
* a worker or worklet entry chunk bakes to, or `null` to keep the runtime form. The
|
|
3379
|
+
* gate and the build are asked together so every call site agrees on both — the
|
|
3380
|
+
* `new Worker(...)` emit, and the resource hint `ResourceHintPlugin` spells for it.
|
|
3381
|
+
* @param {string | undefined} overridePublicPath a `publicPath` set on the worker itself
|
|
3382
|
+
* @param {Chunk} chunk the worker's entry chunk
|
|
3383
|
+
* @param {Module} module the module the reference is emitted into
|
|
3384
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3385
|
+
* @returns {string | null} a quoted literal, or `null` to fall back
|
|
3386
|
+
*/
|
|
3387
|
+
getAnalyzableWorkerUrl(overridePublicPath, chunk, module, chunkGraph) {
|
|
3388
|
+
// Without an id nothing can name the chunk in a stand-in.
|
|
3389
|
+
if (
|
|
3390
|
+
chunk.id === null ||
|
|
3391
|
+
!this.supportsAnalyzable("url", chunkGraph, module)
|
|
3392
|
+
) {
|
|
3393
|
+
return null;
|
|
3394
|
+
}
|
|
3395
|
+
return this._getAnalyzableChunkSpecifier(
|
|
3396
|
+
overridePublicPath,
|
|
3397
|
+
chunk,
|
|
3398
|
+
module,
|
|
3399
|
+
chunkGraph
|
|
3400
|
+
);
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3314
3403
|
/**
|
|
3315
3404
|
* Static literal specifier (already quoted) for a `new URL(<here>, import.meta.url)`
|
|
3316
3405
|
* or `import(<here>)` pointing at `chunk`'s JS file, or `null` when it can't be known
|
|
@@ -3320,12 +3409,11 @@ class RuntimeTemplate {
|
|
|
3320
3409
|
* @param {Module | undefined} consumingModule the module the reference is emitted
|
|
3321
3410
|
* into, or `undefined` when `consumingChunks` names where it goes instead
|
|
3322
3411
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3323
|
-
* @param {RuntimeRequirements=} runtimeRequirements set when the caller wraps the result in
|
|
3324
|
-
* `new URL(...)` and so accepts a runtime public path prefix around the literal filename
|
|
3325
3412
|
* @param {Chunk[]=} consumingChunks the chunks the reference is written into, where
|
|
3326
3413
|
* they are known without a module to read them from
|
|
3327
3414
|
* @param {string=} sourceType which half of the chunk is named — its javascript by
|
|
3328
3415
|
* default, or its stylesheet
|
|
3416
|
+
* @param {boolean=} hot whether a hot update can re-run what is written
|
|
3329
3417
|
* @returns {string | null} a JS string literal or expression, or `null` to fall back to the runtime form
|
|
3330
3418
|
*/
|
|
3331
3419
|
_getAnalyzableChunkSpecifier(
|
|
@@ -3333,120 +3421,113 @@ class RuntimeTemplate {
|
|
|
3333
3421
|
chunk,
|
|
3334
3422
|
consumingModule,
|
|
3335
3423
|
chunkGraph,
|
|
3336
|
-
runtimeRequirements,
|
|
3337
3424
|
consumingChunks,
|
|
3338
|
-
sourceType = JAVASCRIPT_TYPE
|
|
3425
|
+
sourceType = JAVASCRIPT_TYPE,
|
|
3426
|
+
hot = isHotModule(consumingModule)
|
|
3339
3427
|
) {
|
|
3340
3428
|
const { compilation } = this;
|
|
3341
3429
|
const { outputOptions } = compilation;
|
|
3342
3430
|
const naming = CHUNK_ASSET_NAMING.get(sourceType);
|
|
3343
3431
|
// Nothing here names this type's asset, so nothing can spell where it will be.
|
|
3344
3432
|
if (naming === undefined) return null;
|
|
3345
|
-
const template = this.
|
|
3346
|
-
naming.template(chunk, outputOptions),
|
|
3347
|
-
chunk,
|
|
3348
|
-
sourceType
|
|
3349
|
-
);
|
|
3433
|
+
const template = this._chunkAssetTemplate(chunk, sourceType);
|
|
3350
3434
|
if (template === null) return null;
|
|
3351
3435
|
// A hashed name is settled long after this code is generated, so a stand-in is
|
|
3352
3436
|
// emitted and filled in once the hash exists.
|
|
3353
3437
|
const deferred = template === undefined || HASH_IN_FILENAME.test(template);
|
|
3354
3438
|
// An id names the chunk in the stand-in, and one nothing could resolve would
|
|
3355
|
-
// reach the bundle verbatim. The whole name is re-resolved later
|
|
3356
|
-
//
|
|
3357
|
-
// One of the two always names where the reference goes.
|
|
3439
|
+
// reach the bundle verbatim. The whole name is re-resolved later, so any hash
|
|
3440
|
+
// spelling is fine here; one of the two always names the destination.
|
|
3358
3441
|
const chunks =
|
|
3359
3442
|
consumingChunks ||
|
|
3360
3443
|
this._moduleChunks(/** @type {Module} */ (consumingModule), chunkGraph);
|
|
3361
|
-
//
|
|
3362
|
-
//
|
|
3363
|
-
|
|
3444
|
+
// An id names the chunk in the stand-in; `blockPromise` drops an id-less chunk
|
|
3445
|
+
// before asking, so the guard only keeps `null` out of a name.
|
|
3446
|
+
if (chunk.id === null) return null;
|
|
3447
|
+
// A runtime module is generated in its chunk's round of `createHash`, where a
|
|
3448
|
+
// hashed name settled earlier exists: spelled, so a hot update carries the new one.
|
|
3449
|
+
const settled =
|
|
3364
3450
|
deferred &&
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
//
|
|
3370
|
-
//
|
|
3371
|
-
const canReserve =
|
|
3372
|
-
chunk.id !== null && !cycles && this._canDeferAnalyzableName(chunks);
|
|
3373
|
-
// A content-named consumer bakes anyway when this chunk settles first: the fold
|
|
3374
|
-
// puts the name into its hash. Only what `_foldsWholeName` covers, though.
|
|
3451
|
+
template !== undefined &&
|
|
3452
|
+
this._hashedNamePresent(chunk, template, sourceType) &&
|
|
3453
|
+
this._namesBeforeAll(chunk, chunks);
|
|
3454
|
+
const canReserve = this._canDeferAnalyzableName(chunks);
|
|
3455
|
+
// A content-named consumer folds this name into its hash when it settles first;
|
|
3456
|
+
// what the fold cannot cover is repaired instead.
|
|
3375
3457
|
const canFold = !canReserve && this._namesBeforeAll(chunk, chunks);
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
return null;
|
|
3387
|
-
};
|
|
3388
|
-
if (deferred && !canReserve && !canFold) return cannotReserve();
|
|
3389
|
-
const filename = deferred
|
|
3390
|
-
? ""
|
|
3391
|
-
: compilation.getPath(/** @type {string} */ (template), {
|
|
3392
|
-
chunk,
|
|
3393
|
-
// Matches what names the asset, or a placeholder resolved here would
|
|
3394
|
-
// not be the one on disk.
|
|
3395
|
-
runtime: chunk.runtime,
|
|
3396
|
-
contentHashType: sourceType
|
|
3397
|
-
});
|
|
3458
|
+
const filename =
|
|
3459
|
+
deferred && !settled
|
|
3460
|
+
? ""
|
|
3461
|
+
: compilation.getPath(/** @type {string} */ (template), {
|
|
3462
|
+
chunk,
|
|
3463
|
+
// Matches what names the asset, or a placeholder resolved here would
|
|
3464
|
+
// not be the one on disk.
|
|
3465
|
+
runtime: chunk.runtime,
|
|
3466
|
+
contentHashType: sourceType
|
|
3467
|
+
});
|
|
3398
3468
|
/**
|
|
3399
3469
|
* @param {SpecifierPart[]} prefix what goes in front of the chunk's filename
|
|
3400
|
-
* @returns {string
|
|
3401
|
-
* recipe needs a stand-in that cannot be reserved
|
|
3470
|
+
* @returns {string} the specifier already quoted
|
|
3402
3471
|
*/
|
|
3403
3472
|
const specifier = (prefix) => {
|
|
3404
|
-
if (!deferred) {
|
|
3473
|
+
if (!deferred || settled) {
|
|
3405
3474
|
const text = literalText(prefix);
|
|
3406
3475
|
if (text !== null) return toJsStringLiteral(text + filename);
|
|
3407
3476
|
}
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
}
|
|
3477
|
+
const repair =
|
|
3478
|
+
!canReserve && !(canFold && this._foldsWholeName(prefix, chunks));
|
|
3411
3479
|
return toJsStringLiteral(
|
|
3412
|
-
this._reserveAnalyzableSpecifier(
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3480
|
+
this._reserveAnalyzableSpecifier(
|
|
3481
|
+
this._markedForRepair(repair, [
|
|
3482
|
+
...prefix,
|
|
3483
|
+
// A settled name is carried as text: the fill would spell the same,
|
|
3484
|
+
// but only text of its own moves the runtime module's hash.
|
|
3485
|
+
settled
|
|
3486
|
+
? ["literal", filename]
|
|
3487
|
+
: [naming.standIn, /** @type {ChunkId} */ (chunk.id)]
|
|
3488
|
+
])
|
|
3489
|
+
)
|
|
3416
3490
|
);
|
|
3417
3491
|
};
|
|
3418
3492
|
if (overridePublicPath) {
|
|
3419
|
-
const resolved = this._resolvePublicPathPrefix(
|
|
3420
|
-
overridePublicPath,
|
|
3421
|
-
consumingModule,
|
|
3422
|
-
chunks
|
|
3423
|
-
);
|
|
3493
|
+
const resolved = this._resolvePublicPathPrefix(overridePublicPath);
|
|
3424
3494
|
return resolved === null ? null : specifier(resolved);
|
|
3425
3495
|
}
|
|
3426
3496
|
const { publicPath } = outputOptions;
|
|
3427
3497
|
if (publicPath === "auto") {
|
|
3428
|
-
const { undo } = this._placementOf(chunks);
|
|
3498
|
+
const { undo } = this._placementOf(chunks, hot);
|
|
3429
3499
|
if (undo !== null) return specifier([["literal", undo]]);
|
|
3430
3500
|
// Different depths — no one `../` path is right for every asset the reference
|
|
3431
3501
|
// lands in, so the deferred pass builds each asset's own.
|
|
3432
|
-
|
|
3433
|
-
if (perAsset !== null) return perAsset;
|
|
3434
|
-
// Only a stand-in that could not be reserved reaches here, and `specifier`
|
|
3435
|
-
// has already recorded why.
|
|
3436
|
-
if (deferred || !runtimeRequirements) return null;
|
|
3437
|
-
// No bundler follows a concatenation, but a `new URL(...)` caller still sheds
|
|
3438
|
-
// the `.u(id)` lookup this way; `import()` needs a static specifier.
|
|
3439
|
-
runtimeRequirements.add(RuntimeGlobals.publicPath);
|
|
3440
|
-
return `${RuntimeGlobals.publicPath} + ${toJsStringLiteral(filename)}`;
|
|
3502
|
+
return specifier([["undo", ""]]);
|
|
3441
3503
|
}
|
|
3442
3504
|
const prefix = this._analyzablePathPrefix(
|
|
3443
3505
|
consumingModule,
|
|
3444
3506
|
chunkGraph,
|
|
3445
|
-
chunks
|
|
3507
|
+
chunks,
|
|
3508
|
+
undefined,
|
|
3509
|
+
hot
|
|
3446
3510
|
);
|
|
3447
3511
|
return prefix === null ? null : specifier(prefix);
|
|
3448
3512
|
}
|
|
3449
3513
|
|
|
3514
|
+
/**
|
|
3515
|
+
* The template this chunk's asset of `sourceType` is named by: `undefined` where a
|
|
3516
|
+
* function reads a hash, `null` where nothing here names that type or it answers nothing.
|
|
3517
|
+
* @param {Chunk} chunk the chunk
|
|
3518
|
+
* @param {string} sourceType which asset of the chunk
|
|
3519
|
+
* @returns {string | undefined | null} the template
|
|
3520
|
+
*/
|
|
3521
|
+
_chunkAssetTemplate(chunk, sourceType) {
|
|
3522
|
+
const naming = CHUNK_ASSET_NAMING.get(sourceType);
|
|
3523
|
+
if (naming === undefined) return null;
|
|
3524
|
+
return this._resolveChunkFilenameTemplate(
|
|
3525
|
+
naming.template(chunk, this.outputOptions),
|
|
3526
|
+
chunk,
|
|
3527
|
+
sourceType
|
|
3528
|
+
);
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3450
3531
|
/**
|
|
3451
3532
|
* The parts that go in front of a name so a literal read from the chunk holding it
|
|
3452
3533
|
* reaches what the runtime would. A public path needing no base is the whole answer.
|
|
@@ -3460,18 +3541,24 @@ class RuntimeTemplate {
|
|
|
3460
3541
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3461
3542
|
* @param {Iterable<Chunk>} chunks the chunks a stand-in would be written into
|
|
3462
3543
|
* @param {string=} relativeBase an entry `baseUri` read against the output root
|
|
3544
|
+
* @param {boolean=} hot whether a hot update can re-run what is written
|
|
3463
3545
|
* @returns {SpecifierPart[] | null} the parts, or `null` having recorded why not
|
|
3464
3546
|
*/
|
|
3465
|
-
_analyzablePathPrefix(
|
|
3547
|
+
_analyzablePathPrefix(
|
|
3548
|
+
module,
|
|
3549
|
+
chunkGraph,
|
|
3550
|
+
chunks,
|
|
3551
|
+
relativeBase,
|
|
3552
|
+
hot = isHotModule(module)
|
|
3553
|
+
) {
|
|
3466
3554
|
const publicPath = /** @type {PublicPath} */ (
|
|
3467
3555
|
this.outputOptions.publicPath
|
|
3468
3556
|
);
|
|
3469
3557
|
const shape = this._publicPathShape();
|
|
3470
3558
|
if (shape === undefined) return null;
|
|
3471
|
-
const resolve = () =>
|
|
3472
|
-
this._resolvePublicPathPrefix(publicPath, module, chunks);
|
|
3559
|
+
const resolve = () => this._resolvePublicPathPrefix(publicPath);
|
|
3473
3560
|
if (isBaseIndependent(shape)) return resolve();
|
|
3474
|
-
const { undo, loaded } = this._placementOf(chunks);
|
|
3561
|
+
const { undo, loaded } = this._placementOf(chunks, hot);
|
|
3475
3562
|
// What a chunk the loader fetched climbs back out of. One of no depth leaves
|
|
3476
3563
|
// nothing to climb, and then both answers put the same text in front.
|
|
3477
3564
|
const served = this._publicPathClimb();
|
|
@@ -3483,24 +3570,17 @@ class RuntimeTemplate {
|
|
|
3483
3570
|
// Each knows its own answer, so the fill asks per asset — where each has one,
|
|
3484
3571
|
// and where nothing else goes between the two shapes.
|
|
3485
3572
|
if (relativeBase !== undefined || !this._eachChunkServedOneWay(chunks)) {
|
|
3486
|
-
this._analyzableBailout(module, SERVED_BAILOUT);
|
|
3487
|
-
return null;
|
|
3573
|
+
return this._analyzableBailout(module, SERVED_BAILOUT, null);
|
|
3488
3574
|
}
|
|
3489
3575
|
return [...head, ["unserved", ""]];
|
|
3490
3576
|
}
|
|
3491
3577
|
if (climb !== "" && relativeBase === undefined) return head;
|
|
3492
3578
|
const resolved = resolve();
|
|
3493
3579
|
if (resolved === null) return null;
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
),
|
|
3499
|
-
.../** @type {SpecifierPart[]} */ (
|
|
3500
|
-
relativeBase === undefined ? [] : [["literal", relativeBase]]
|
|
3501
|
-
),
|
|
3502
|
-
...rootedParts(resolved)
|
|
3503
|
-
];
|
|
3580
|
+
if (climb !== "") head.push(["literal", climb]);
|
|
3581
|
+
if (relativeBase !== undefined) head.push(["literal", relativeBase]);
|
|
3582
|
+
head.push(...rootedParts(resolved));
|
|
3583
|
+
return head;
|
|
3504
3584
|
}
|
|
3505
3585
|
|
|
3506
3586
|
/**
|
|
@@ -3512,12 +3592,9 @@ class RuntimeTemplate {
|
|
|
3512
3592
|
* the deferred pass whole instead. A function is called for its value rather than
|
|
3513
3593
|
* read as a template, so one whose answer moves with the hash is called again there.
|
|
3514
3594
|
* @param {PublicPath} publicPath the configured public path
|
|
3515
|
-
* @param {Module=} module the module the reference is emitted into, to record why
|
|
3516
|
-
* a name no stand-in may be reserved for kept the runtime form
|
|
3517
|
-
* @param {Iterable<Chunk>=} chunks the chunks a stand-in would be written into
|
|
3518
3595
|
* @returns {SpecifierPart[] | null} the parts, or `null` when it cannot be known
|
|
3519
3596
|
*/
|
|
3520
|
-
_resolvePublicPathPrefix(publicPath
|
|
3597
|
+
_resolvePublicPathPrefix(publicPath) {
|
|
3521
3598
|
if (typeof publicPath === "function") {
|
|
3522
3599
|
// One that answers nothing to a probe cannot be placed, absolute or not.
|
|
3523
3600
|
if (this._publicPathShape() === undefined) return null;
|
|
@@ -3528,28 +3605,18 @@ class RuntimeTemplate {
|
|
|
3528
3605
|
if (resolved !== null) return [["literal", resolved]];
|
|
3529
3606
|
// Called again by the fill against the compilation hash, so what it answers
|
|
3530
3607
|
// there is that hash by another name.
|
|
3531
|
-
return
|
|
3532
|
-
? [["publicPath", ""]]
|
|
3533
|
-
: null;
|
|
3608
|
+
return [["publicPath", ""]];
|
|
3534
3609
|
}
|
|
3535
3610
|
if (!publicPath.includes("[")) return [["literal", publicPath]];
|
|
3536
3611
|
// A re-encoded digest cannot be spelled by a stand-in, so it stays a template.
|
|
3537
3612
|
if (getTemplatedPathPlugin().usesFullHashDigest(publicPath)) {
|
|
3538
|
-
return
|
|
3539
|
-
? [["template", publicPath]]
|
|
3540
|
-
: null;
|
|
3613
|
+
return [["template", publicPath]];
|
|
3541
3614
|
}
|
|
3542
3615
|
const literal = this.compilation.getPath(
|
|
3543
3616
|
publicPath,
|
|
3544
3617
|
this._deferredFullHashPathData()
|
|
3545
3618
|
);
|
|
3546
|
-
return
|
|
3547
|
-
this._hasReservedFullHash(literal),
|
|
3548
|
-
chunks,
|
|
3549
|
-
module
|
|
3550
|
-
)
|
|
3551
|
-
? [["literal", literal]]
|
|
3552
|
-
: null;
|
|
3619
|
+
return [["literal", literal]];
|
|
3553
3620
|
}
|
|
3554
3621
|
|
|
3555
3622
|
/**
|
|
@@ -3626,11 +3693,6 @@ class RuntimeTemplate {
|
|
|
3626
3693
|
) {
|
|
3627
3694
|
const { publicPath } = this.outputOptions;
|
|
3628
3695
|
const chunks = this._moduleChunks(module, chunkGraph);
|
|
3629
|
-
/**
|
|
3630
|
-
* @param {SpecifierPart[]} parts the whole specifier
|
|
3631
|
-
* @returns {string | null} it already quoted, or `null` when no stand-in may be reserved
|
|
3632
|
-
*/
|
|
3633
|
-
const specifier = (parts) => this._specifierOf(parts, chunks, module);
|
|
3634
3696
|
if (bakePublicPath && publicPath !== "auto") {
|
|
3635
3697
|
const prefix = this._analyzablePathPrefix(
|
|
3636
3698
|
module,
|
|
@@ -3638,30 +3700,28 @@ class RuntimeTemplate {
|
|
|
3638
3700
|
chunks,
|
|
3639
3701
|
relativeBase
|
|
3640
3702
|
);
|
|
3641
|
-
|
|
3703
|
+
if (prefix === null) return null;
|
|
3704
|
+
return this._specifierOf([...prefix, ...file], chunks);
|
|
3642
3705
|
}
|
|
3643
3706
|
// No public path to place it against, so the `../` path back to the output root
|
|
3644
3707
|
// is the whole prefix. Different depths — no one is right for every asset the
|
|
3645
3708
|
// reference is emitted into, so the deferred pass builds each asset's own.
|
|
3646
3709
|
const { undo } = this._modulePlacement(module, chunkGraph);
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
...file
|
|
3653
|
-
]);
|
|
3710
|
+
/** @type {SpecifierPart[]} */
|
|
3711
|
+
const parts = [undo === null ? ["undo", ""] : ["literal", undo]];
|
|
3712
|
+
if (relativeBase !== undefined) parts.push(["literal", relativeBase]);
|
|
3713
|
+
parts.push(...file);
|
|
3714
|
+
return this._specifierOf(parts, chunks);
|
|
3654
3715
|
}
|
|
3655
3716
|
|
|
3656
3717
|
/**
|
|
3657
3718
|
* Static `new URL(<file>, import.meta.url)` for every stylesheet a runtime can load,
|
|
3658
|
-
* keyed by chunk id, or `null` when
|
|
3719
|
+
* keyed by chunk id, or `null` when they have to keep the runtime
|
|
3659
3720
|
* `publicPath + getChunkCssFilename(id)` form. Both the runtime module reading them
|
|
3660
3721
|
* and the plugin declaring what it needs ask this, so the two always agree. The
|
|
3661
3722
|
* runtime hands an absolute url string to `link.href`, and so does this — the browser
|
|
3662
3723
|
* resolves the element against the document, which is not where the chunk sits, and
|
|
3663
|
-
* the loader reads the url as text either way.
|
|
3664
|
-
* that also carries the hot handler; see below.
|
|
3724
|
+
* the loader reads the url as text either way.
|
|
3665
3725
|
* @param {Chunk} runtimeChunk the chunk holding the stylesheet loader
|
|
3666
3726
|
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3667
3727
|
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
|
|
@@ -3698,7 +3758,7 @@ class RuntimeTemplate {
|
|
|
3698
3758
|
/**
|
|
3699
3759
|
* Static `new URL(<file>, import.meta.url).href` for every javascript chunk a
|
|
3700
3760
|
* runtime can hint at with `<link rel="prefetch"/"modulepreload">`, keyed by chunk
|
|
3701
|
-
* id, or `null` when
|
|
3761
|
+
* id, or `null` when they have to keep the runtime
|
|
3702
3762
|
* `publicPath + getChunkScriptFilename(id)` form. Both the runtime module reading
|
|
3703
3763
|
* them and the plugin declaring what it needs ask this, so the two always agree.
|
|
3704
3764
|
* @param {Chunk} runtimeChunk the chunk holding the hint handlers
|
|
@@ -3722,11 +3782,9 @@ class RuntimeTemplate {
|
|
|
3722
3782
|
);
|
|
3723
3783
|
/** @type {Set<ChunkId>} */
|
|
3724
3784
|
const hinted = new Set();
|
|
3725
|
-
for (const
|
|
3726
|
-
for (const
|
|
3727
|
-
for (const id of
|
|
3728
|
-
hinted.add(id);
|
|
3729
|
-
}
|
|
3785
|
+
for (const byParent of Object.values(orders)) {
|
|
3786
|
+
for (const ids of Object.values(byParent)) {
|
|
3787
|
+
for (const id of ids) hinted.add(id);
|
|
3730
3788
|
}
|
|
3731
3789
|
}
|
|
3732
3790
|
/** @type {Chunk[]} */
|
|
@@ -3744,6 +3802,146 @@ class RuntimeTemplate {
|
|
|
3744
3802
|
);
|
|
3745
3803
|
}
|
|
3746
3804
|
|
|
3805
|
+
/**
|
|
3806
|
+
* Why no chunk import of this build can be a native `import()`, read from the
|
|
3807
|
+
* output configuration alone, or `null` when nothing in it rules one out.
|
|
3808
|
+
* @returns {string | null} the reason
|
|
3809
|
+
*/
|
|
3810
|
+
_chunkImportOutputReason() {
|
|
3811
|
+
const { chunkFormat, importFunctionName } = this.outputOptions;
|
|
3812
|
+
if (chunkFormat !== "module") {
|
|
3813
|
+
return `output.chunkFormat is ${JSON.stringify(chunkFormat)}, so chunks are not read through a native import()`;
|
|
3814
|
+
}
|
|
3815
|
+
if (importFunctionName !== "import") {
|
|
3816
|
+
return `output.importFunctionName is ${JSON.stringify(importFunctionName)}, so the call site is not a native import()`;
|
|
3817
|
+
}
|
|
3818
|
+
return null;
|
|
3819
|
+
}
|
|
3820
|
+
|
|
3821
|
+
/**
|
|
3822
|
+
* Records that this runtime reads its chunks some way other than a native
|
|
3823
|
+
* `import()`, so no literal can name what it loads. Recorded on the entries that
|
|
3824
|
+
* chose it, which is where the setting behind it lives.
|
|
3825
|
+
* @param {Chunk} chunk the runtime chunk
|
|
3826
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3827
|
+
* @returns {void}
|
|
3828
|
+
*/
|
|
3829
|
+
reportChunkImportBailout(chunk, chunkGraph) {
|
|
3830
|
+
if (!this.outputOptions.module) return;
|
|
3831
|
+
const entryOptions = chunk.getEntryOptions();
|
|
3832
|
+
const chunkLoading =
|
|
3833
|
+
entryOptions && entryOptions.chunkLoading !== undefined
|
|
3834
|
+
? entryOptions.chunkLoading
|
|
3835
|
+
: this.outputOptions.chunkLoading;
|
|
3836
|
+
if (chunkLoading === "import") return;
|
|
3837
|
+
const subject = entryOptions && entryOptions.worker ? "worker" : "runtime";
|
|
3838
|
+
const reason = `this ${subject} loads its chunks with ${JSON.stringify(chunkLoading)}, not "import"`;
|
|
3839
|
+
for (const module of chunkGraph.getChunkEntryModulesIterable(chunk)) {
|
|
3840
|
+
this._analyzableBailout(module, reason, false);
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
/**
|
|
3845
|
+
* The chunks this loader can be handed an id for: the ones held by a group outside
|
|
3846
|
+
* the initial wave, which is what an `import()` or a context map turns into an id.
|
|
3847
|
+
* @param {Chunk} runtimeChunk the chunk holding the chunk loader
|
|
3848
|
+
* @returns {Set<Chunk>} the chunks reachable from here through a non-initial group
|
|
3849
|
+
*/
|
|
3850
|
+
_loadableChunks(runtimeChunk) {
|
|
3851
|
+
const queue = new Set(runtimeChunk.groupsIterable);
|
|
3852
|
+
/** @type {Set<Chunk>} */
|
|
3853
|
+
const chunks = new Set();
|
|
3854
|
+
for (const group of queue) {
|
|
3855
|
+
if (!group.isInitial()) {
|
|
3856
|
+
for (const chunk of group.chunks) chunks.add(chunk);
|
|
3857
|
+
}
|
|
3858
|
+
for (const child of group.childrenIterable) queue.add(child);
|
|
3859
|
+
}
|
|
3860
|
+
return chunks;
|
|
3861
|
+
}
|
|
3862
|
+
|
|
3863
|
+
/**
|
|
3864
|
+
* Whether the loader still needs to build a url from a chunk id, which is the case
|
|
3865
|
+
* for a chunk it can be asked for that `analyzableChunkImports` leaves unnamed: one
|
|
3866
|
+
* carrying a runtime of its own, or one a second entrypoint has at startup.
|
|
3867
|
+
* @param {Chunk} runtimeChunk the chunk holding the chunk loader
|
|
3868
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3869
|
+
* @returns {boolean} true when an id the map does not hold can reach the loader
|
|
3870
|
+
*/
|
|
3871
|
+
chunkImportsNeedRuntimeUrl(runtimeChunk, chunkGraph) {
|
|
3872
|
+
const installed = new Set(runtimeChunk.getAllInitialChunks());
|
|
3873
|
+
for (const chunk of this._loadableChunks(runtimeChunk)) {
|
|
3874
|
+
if (chunk === runtimeChunk) continue;
|
|
3875
|
+
if (!chunk.hasRuntime() && !installed.has(chunk)) continue;
|
|
3876
|
+
if (JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)) return true;
|
|
3877
|
+
}
|
|
3878
|
+
return false;
|
|
3879
|
+
}
|
|
3880
|
+
|
|
3881
|
+
/**
|
|
3882
|
+
* A literal `import()` specifier for every javascript chunk a runtime loads on
|
|
3883
|
+
* demand, keyed by chunk id, or `null` when one of them cannot be named here. The
|
|
3884
|
+
* map is written into the runtime chunk rather than at each import site, so a
|
|
3885
|
+
* hashed chunk name reaches no module that imports it.
|
|
3886
|
+
* @param {Chunk} runtimeChunk the chunk holding the chunk loader
|
|
3887
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3888
|
+
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what that chunk needs
|
|
3889
|
+
* @param {Module=} consumingModule the runtime module, where one exists to report against
|
|
3890
|
+
* @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
|
|
3891
|
+
*/
|
|
3892
|
+
analyzableChunkImports(
|
|
3893
|
+
runtimeChunk,
|
|
3894
|
+
chunkGraph,
|
|
3895
|
+
runtimeRequirements,
|
|
3896
|
+
consumingModule
|
|
3897
|
+
) {
|
|
3898
|
+
// The runtime names the scope `__webpack_public_path__` belongs to, so the
|
|
3899
|
+
// answer holds whether or not a runtime module is there to ask about.
|
|
3900
|
+
if (
|
|
3901
|
+
!this.supportsAnalyzable(
|
|
3902
|
+
"import",
|
|
3903
|
+
chunkGraph,
|
|
3904
|
+
consumingModule,
|
|
3905
|
+
runtimeChunk.runtime
|
|
3906
|
+
)
|
|
3907
|
+
) {
|
|
3908
|
+
return null;
|
|
3909
|
+
}
|
|
3910
|
+
// An initial chunk and one carrying a runtime are both reached by a static
|
|
3911
|
+
// import, so naming either here would only make two hashes chase each other.
|
|
3912
|
+
const installed = new Set(runtimeChunk.getAllInitialChunks());
|
|
3913
|
+
/** @type {Chunk[]} */
|
|
3914
|
+
const chunks = [];
|
|
3915
|
+
for (const chunk of runtimeChunk.getAllReferencedChunks()) {
|
|
3916
|
+
if (
|
|
3917
|
+
chunk === runtimeChunk ||
|
|
3918
|
+
chunk.hasRuntime() ||
|
|
3919
|
+
installed.has(chunk) ||
|
|
3920
|
+
!JavascriptModulesPlugin.chunkHasJs(chunk, chunkGraph)
|
|
3921
|
+
) {
|
|
3922
|
+
continue;
|
|
3923
|
+
}
|
|
3924
|
+
chunks.push(chunk);
|
|
3925
|
+
}
|
|
3926
|
+
const specifiers = this._analyzableChunkSpecifiers(
|
|
3927
|
+
chunks,
|
|
3928
|
+
chunkGraph,
|
|
3929
|
+
consumingModule,
|
|
3930
|
+
[runtimeChunk],
|
|
3931
|
+
JAVASCRIPT_TYPE,
|
|
3932
|
+
runtimeRequirements
|
|
3933
|
+
);
|
|
3934
|
+
if (specifiers === null) return null;
|
|
3935
|
+
for (const [id, specifier] of specifiers) {
|
|
3936
|
+
// A bare specifier is a package name, so spell it relative the way the
|
|
3937
|
+
// runtime form's `.p + <file>` would have resolved it.
|
|
3938
|
+
if (!RESOLVABLE_SPECIFIER_REGEXP.test(specifier.slice(1))) {
|
|
3939
|
+
specifiers.set(id, `"./${specifier.slice(1)}`);
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
return specifiers;
|
|
3943
|
+
}
|
|
3944
|
+
|
|
3747
3945
|
/**
|
|
3748
3946
|
* The urls of one asset of each of `chunks`, written out so they can be read by
|
|
3749
3947
|
* chunk id, or `null` as soon as one of them cannot be named here.
|
|
@@ -3763,16 +3961,51 @@ class RuntimeTemplate {
|
|
|
3763
3961
|
sourceType,
|
|
3764
3962
|
runtimeRequirements
|
|
3765
3963
|
) {
|
|
3766
|
-
|
|
3767
|
-
// to HMR — analyzable output is what ships.
|
|
3768
|
-
if (
|
|
3769
|
-
runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers) ||
|
|
3770
|
-
!this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)
|
|
3771
|
-
) {
|
|
3964
|
+
if (!this.supportsAnalyzable("url-runtime", chunkGraph, consumingModule)) {
|
|
3772
3965
|
return null;
|
|
3773
3966
|
}
|
|
3967
|
+
const urls = this._analyzableChunkSpecifiers(
|
|
3968
|
+
chunks,
|
|
3969
|
+
chunkGraph,
|
|
3970
|
+
consumingModule,
|
|
3971
|
+
consumingChunks,
|
|
3972
|
+
sourceType,
|
|
3973
|
+
runtimeRequirements
|
|
3974
|
+
);
|
|
3975
|
+
if (urls === null) return null;
|
|
3976
|
+
for (const [id, specifier] of urls) {
|
|
3977
|
+
urls.set(id, `${this.importMetaUrl(specifier)}.href`);
|
|
3978
|
+
}
|
|
3979
|
+
return urls;
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
/**
|
|
3983
|
+
* The quoted specifier naming one asset of each of `chunks`, keyed by chunk id, or
|
|
3984
|
+
* `null` as soon as one of them cannot be named here. What the name is read against
|
|
3985
|
+
* is the caller's: a url resolves it, an `import()` hands it to the loader.
|
|
3986
|
+
* @param {Iterable<Chunk>} chunks the chunks whose asset is wanted
|
|
3987
|
+
* @param {ChunkGraph} chunkGraph the chunk graph
|
|
3988
|
+
* @param {Module | undefined} consumingModule the runtime module, where one exists to report against
|
|
3989
|
+
* @param {Chunk[]} consumingChunks the chunks the specifiers are written into
|
|
3990
|
+
* @param {string} sourceType which asset of each chunk to name
|
|
3991
|
+
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements what the runtime chunk needs
|
|
3992
|
+
* @returns {Map<ChunkId, string> | null} the specifiers, or `null` to keep the runtime form
|
|
3993
|
+
*/
|
|
3994
|
+
_analyzableChunkSpecifiers(
|
|
3995
|
+
chunks,
|
|
3996
|
+
chunkGraph,
|
|
3997
|
+
consumingModule,
|
|
3998
|
+
consumingChunks,
|
|
3999
|
+
sourceType,
|
|
4000
|
+
runtimeRequirements
|
|
4001
|
+
) {
|
|
4002
|
+
// A hot update re-ships the runtime module only when its own code changes, so
|
|
4003
|
+
// each name has to be text nothing but an id joining or leaving the map can move.
|
|
4004
|
+
const hot = runtimeRequirements.has(
|
|
4005
|
+
RuntimeGlobals.hmrDownloadUpdateHandlers
|
|
4006
|
+
);
|
|
3774
4007
|
/** @type {Map<ChunkId, string>} */
|
|
3775
|
-
const
|
|
4008
|
+
const specifiers = new Map();
|
|
3776
4009
|
for (const chunk of chunks) {
|
|
3777
4010
|
if (chunk.id === null) continue;
|
|
3778
4011
|
const specifier = this._getAnalyzableChunkSpecifier(
|
|
@@ -3780,14 +4013,74 @@ class RuntimeTemplate {
|
|
|
3780
4013
|
chunk,
|
|
3781
4014
|
consumingModule,
|
|
3782
4015
|
chunkGraph,
|
|
3783
|
-
undefined,
|
|
3784
4016
|
consumingChunks,
|
|
3785
|
-
sourceType
|
|
4017
|
+
sourceType,
|
|
4018
|
+
hot
|
|
3786
4019
|
);
|
|
3787
4020
|
if (specifier === null) return null;
|
|
3788
|
-
|
|
4021
|
+
if (
|
|
4022
|
+
hot &&
|
|
4023
|
+
!this._settledUnderHot(specifier, chunk, sourceType, consumingChunks)
|
|
4024
|
+
) {
|
|
4025
|
+
return this._analyzableBailout(consumingModule, HOT_NAME_BAILOUT, null);
|
|
4026
|
+
}
|
|
4027
|
+
specifiers.set(chunk.id, specifier);
|
|
4028
|
+
}
|
|
4029
|
+
return specifiers.size > 0 ? specifiers : null;
|
|
4030
|
+
}
|
|
4031
|
+
|
|
4032
|
+
/**
|
|
4033
|
+
* Whether a url a hot update re-ships moves only with the runtime module's own text:
|
|
4034
|
+
* spelled here, or a stand-in of each asset's depth and a hash-free or settled name.
|
|
4035
|
+
* @param {string} specifier the specifier already quoted
|
|
4036
|
+
* @param {Chunk} chunk the chunk it names
|
|
4037
|
+
* @param {string} sourceType which asset of the chunk it names
|
|
4038
|
+
* @param {Chunk[]} consumingChunks the chunks the map is written into
|
|
4039
|
+
* @returns {boolean} true when no update moves what the fill spells
|
|
4040
|
+
*/
|
|
4041
|
+
_settledUnderHot(specifier, chunk, sourceType, consumingChunks) {
|
|
4042
|
+
const match = ANALYZABLE_TOKEN_PAYLOAD.exec(specifier);
|
|
4043
|
+
if (match === null) return true;
|
|
4044
|
+
const parts = RuntimeTemplate._readAnalyzableSpecifier(match[1]);
|
|
4045
|
+
if (parts === null) return false;
|
|
4046
|
+
for (const [kind, value] of parts) {
|
|
4047
|
+
if (kind === "undo") continue;
|
|
4048
|
+
if (kind === "literal" && !this._hasReservedFullHash(String(value))) {
|
|
4049
|
+
continue;
|
|
4050
|
+
}
|
|
4051
|
+
if (!CHUNK_SPECIFIER_PART_KINDS.has(kind)) return false;
|
|
4052
|
+
}
|
|
4053
|
+
const template = this._chunkAssetTemplate(chunk, sourceType);
|
|
4054
|
+
return (
|
|
4055
|
+
typeof template === "string" &&
|
|
4056
|
+
(!HASH_IN_FILENAME.test(template) ||
|
|
4057
|
+
this._hashedNameSettledBefore(chunk, template, consumingChunks))
|
|
4058
|
+
);
|
|
4059
|
+
}
|
|
4060
|
+
|
|
4061
|
+
/**
|
|
4062
|
+
* The `../` path from a chunk's hot update file, which re-runs its modules, back to
|
|
4063
|
+
* the output root. Hashes are neutralized; the chunk's own id may add a directory.
|
|
4064
|
+
* @param {Chunk} chunk the chunk being updated
|
|
4065
|
+
* @returns {string} the path back to the output root
|
|
4066
|
+
*/
|
|
4067
|
+
_hotUpdateUndo(chunk) {
|
|
4068
|
+
const cached = this._hotUpdateUndoByChunk.get(chunk);
|
|
4069
|
+
if (cached !== undefined) return cached;
|
|
4070
|
+
const { outputOptions } = this;
|
|
4071
|
+
if (this._hotUpdateShapeText === undefined) {
|
|
4072
|
+
this._hotUpdateShapeText = outputOptions.hotUpdateChunkFilename.replace(
|
|
4073
|
+
HASH_IN_FILENAME_GLOBAL,
|
|
4074
|
+
"x"
|
|
4075
|
+
);
|
|
3789
4076
|
}
|
|
3790
|
-
|
|
4077
|
+
const undo = getUndoPath(
|
|
4078
|
+
this.compilation.getPath(this._hotUpdateShapeText, { chunk }),
|
|
4079
|
+
/** @type {string} */ (outputOptions.path),
|
|
4080
|
+
true
|
|
4081
|
+
);
|
|
4082
|
+
this._hotUpdateUndoByChunk.set(chunk, undo);
|
|
4083
|
+
return undo;
|
|
3791
4084
|
}
|
|
3792
4085
|
|
|
3793
4086
|
/**
|
|
@@ -3852,20 +4145,20 @@ class RuntimeTemplate {
|
|
|
3852
4145
|
try {
|
|
3853
4146
|
// Everything the naming call is given except the hashes, so only a hash can
|
|
3854
4147
|
// make the two answers differ.
|
|
3855
|
-
const template =
|
|
3856
|
-
|
|
3857
|
-
|
|
4148
|
+
const template = probeTemplateName(
|
|
4149
|
+
filenameTemplate,
|
|
4150
|
+
chunk,
|
|
3858
4151
|
contentHashType,
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
const probe =
|
|
3863
|
-
|
|
3864
|
-
|
|
4152
|
+
HASH_PROBE,
|
|
4153
|
+
true
|
|
4154
|
+
);
|
|
4155
|
+
const probe = probeTemplateName(
|
|
4156
|
+
filenameTemplate,
|
|
4157
|
+
chunk,
|
|
3865
4158
|
contentHashType,
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
4159
|
+
HASH_PROBE_ALTERNATE,
|
|
4160
|
+
false
|
|
4161
|
+
);
|
|
3869
4162
|
return template === probe ? template : undefined;
|
|
3870
4163
|
} catch (_error) {
|
|
3871
4164
|
// Nothing to report: the probe is given strictly more than the naming call,
|
|
@@ -3882,21 +4175,16 @@ class RuntimeTemplate {
|
|
|
3882
4175
|
* @returns {boolean} true when every runtime reaching it fetches
|
|
3883
4176
|
*/
|
|
3884
4177
|
_wasmModuleFetches(module, chunkGraph) {
|
|
3885
|
-
|
|
3886
|
-
|
|
4178
|
+
const { onlyFetching } = this._wasmGroups();
|
|
4179
|
+
let placed = false;
|
|
3887
4180
|
for (const moduleRuntime of chunkGraph.getModuleRuntimes(module)) {
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
4181
|
+
for (const group of this._wasmGroupsOf(moduleRuntime)) {
|
|
4182
|
+
placed = true;
|
|
4183
|
+
if (!onlyFetching.get(group)) return false;
|
|
4184
|
+
}
|
|
3891
4185
|
}
|
|
3892
4186
|
// In no runtime at all nothing named a loader, so `output` answers.
|
|
3893
|
-
|
|
3894
|
-
const only = this._wasmGroupOnlyFetches();
|
|
3895
|
-
const groups = this._wasmRuntimeGroups();
|
|
3896
|
-
for (const key of keys) {
|
|
3897
|
-
if (!only.get(this._wasmGroupOf(groups, key))) return false;
|
|
3898
|
-
}
|
|
3899
|
-
return true;
|
|
4187
|
+
return placed || this.outputOptions.wasmLoading === "fetch";
|
|
3900
4188
|
}
|
|
3901
4189
|
|
|
3902
4190
|
/**
|
|
@@ -3998,7 +4286,7 @@ class RuntimeTemplate {
|
|
|
3998
4286
|
* @returns {string} the stand-in to emit
|
|
3999
4287
|
*/
|
|
4000
4288
|
_reserveAnalyzableSpecifier(parts) {
|
|
4001
|
-
return
|
|
4289
|
+
return `${ANALYZABLE_TOKEN_PREFIX}${Buffer.from(JSON.stringify(parts))
|
|
4002
4290
|
.toString("base64")
|
|
4003
4291
|
.replace(/\+/g, "-")
|
|
4004
4292
|
.replace(/\//g, "_")
|
|
@@ -4059,20 +4347,34 @@ class RuntimeTemplate {
|
|
|
4059
4347
|
compilation.hooks.processAssets.tapPromise(
|
|
4060
4348
|
{
|
|
4061
4349
|
name: PASS_NAME,
|
|
4062
|
-
// Before source maps are written and before a minifier runs
|
|
4063
|
-
// the asset
|
|
4064
|
-
// Every hash it reads is
|
|
4065
|
-
// every `processAssets` stage — and `RealContentHashPlugin` still repairs
|
|
4066
|
-
// the names afterwards.
|
|
4350
|
+
// Before source maps are written and before a minifier runs, since both
|
|
4351
|
+
// read the asset and a stand-in differs in length from what replaces it.
|
|
4352
|
+
// Every hash it reads is settled: `createHash` precedes every stage.
|
|
4067
4353
|
stage: getCompilation().PROCESS_ASSETS_STAGE_DERIVED
|
|
4068
4354
|
},
|
|
4069
4355
|
async () => {
|
|
4070
4356
|
const { outputOptions } = compilation;
|
|
4071
4357
|
const fullHash = compilation.hash;
|
|
4358
|
+
// The assets a stand-in landed in whose hashed name has to be brought
|
|
4359
|
+
// back in line, which `RealContentHashPlugin` then does.
|
|
4360
|
+
/** @type {Set<string>} */
|
|
4361
|
+
const repairedAssets = new Set();
|
|
4072
4362
|
/** @type {Map<string, Chunk> | undefined} */
|
|
4073
4363
|
let chunksById;
|
|
4074
4364
|
/** @type {Map<string, Chunk> | undefined} */
|
|
4075
4365
|
let chunkByAsset;
|
|
4366
|
+
/** @type {string | undefined} */
|
|
4367
|
+
let publicPathText;
|
|
4368
|
+
// One value for the whole pass, however many stand-ins read it.
|
|
4369
|
+
const resolvedPublicPath = () => {
|
|
4370
|
+
if (publicPathText === undefined) {
|
|
4371
|
+
publicPathText = compilation.getPath(
|
|
4372
|
+
outputOptions.publicPath || "",
|
|
4373
|
+
{}
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
return publicPathText;
|
|
4377
|
+
};
|
|
4076
4378
|
/**
|
|
4077
4379
|
* @param {string} name an emitted asset's name
|
|
4078
4380
|
* @returns {Chunk | undefined} the chunk it was emitted for
|
|
@@ -4111,7 +4413,9 @@ class RuntimeTemplate {
|
|
|
4111
4413
|
let base;
|
|
4112
4414
|
let specifier = "";
|
|
4113
4415
|
for (const [kind, value] of parts) {
|
|
4114
|
-
if (kind === "
|
|
4416
|
+
if (kind === "repair") {
|
|
4417
|
+
repairedAssets.add(assetName);
|
|
4418
|
+
} else if (kind === "base") {
|
|
4115
4419
|
base = /** @type {string} */ (value);
|
|
4116
4420
|
} else if (kind === "literal") {
|
|
4117
4421
|
specifier += value;
|
|
@@ -4127,10 +4431,7 @@ class RuntimeTemplate {
|
|
|
4127
4431
|
{}
|
|
4128
4432
|
);
|
|
4129
4433
|
} else if (kind === "publicPath") {
|
|
4130
|
-
specifier +=
|
|
4131
|
-
outputOptions.publicPath || "",
|
|
4132
|
-
{}
|
|
4133
|
-
);
|
|
4434
|
+
specifier += resolvedPublicPath();
|
|
4134
4435
|
} else if (kind === "unserved") {
|
|
4135
4436
|
const holder = chunkOf(assetName);
|
|
4136
4437
|
if (holder === undefined) return null;
|
|
@@ -4141,10 +4442,7 @@ class RuntimeTemplate {
|
|
|
4141
4442
|
compilation.runtimeTemplate._chunkPlacement(holder).loaded ===
|
|
4142
4443
|
false
|
|
4143
4444
|
) {
|
|
4144
|
-
const path =
|
|
4145
|
-
outputOptions.publicPath || "",
|
|
4146
|
-
{}
|
|
4147
|
-
);
|
|
4445
|
+
const path = resolvedPublicPath();
|
|
4148
4446
|
// The `../` already reached the root this is read from.
|
|
4149
4447
|
specifier += path.startsWith("./") ? path.slice(2) : path;
|
|
4150
4448
|
}
|
|
@@ -4188,7 +4486,7 @@ class RuntimeTemplate {
|
|
|
4188
4486
|
// the chunk loader does. A literal part may still carry a stand-in of its own,
|
|
4189
4487
|
// so finish those here rather than scanning again.
|
|
4190
4488
|
return fillFullHash(
|
|
4191
|
-
|
|
4489
|
+
RESOLVABLE_SPECIFIER_REGEXP.test(specifier)
|
|
4192
4490
|
? specifier
|
|
4193
4491
|
: `./${specifier}`
|
|
4194
4492
|
);
|
|
@@ -4241,6 +4539,8 @@ class RuntimeTemplate {
|
|
|
4241
4539
|
|
|
4242
4540
|
tasks.push({ name, source, replacements });
|
|
4243
4541
|
}
|
|
4542
|
+
compilation.runtimeTemplate._analyzableRepairedAssets =
|
|
4543
|
+
repairedAssets;
|
|
4244
4544
|
if (tasks.length === 0) return;
|
|
4245
4545
|
|
|
4246
4546
|
await Promise.all(
|