@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
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
"use strict";
|
|
6
6
|
|
|
7
|
+
const { basename, extname } = require("path");
|
|
7
8
|
const { pathToFileURL } = require("url");
|
|
8
9
|
const { AsyncSeriesHook, AsyncSeriesWaterfallHook } = require("tapable");
|
|
9
10
|
const { RawSource } = require("webpack-sources");
|
|
@@ -19,10 +20,18 @@ const ConstDependency = require("../dependencies/ConstDependency");
|
|
|
19
20
|
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
|
|
20
21
|
const WebpackError = require("../errors/WebpackError");
|
|
21
22
|
const JavascriptModulesPlugin = require("../javascript/JavascriptModulesPlugin");
|
|
22
|
-
const
|
|
23
|
+
const ConcatenatedModule = require("../optimize/ConcatenatedModule");
|
|
24
|
+
const {
|
|
25
|
+
compareModulesByFullName,
|
|
26
|
+
compareModulesByIdentifier
|
|
27
|
+
} = require("../util/comparators");
|
|
23
28
|
const createHash = require("../util/createHash");
|
|
24
29
|
const createHooksRegistry = require("../util/createHooksRegistry");
|
|
25
|
-
const {
|
|
30
|
+
const {
|
|
31
|
+
getUndoPath,
|
|
32
|
+
makePathsRelative,
|
|
33
|
+
parseResource
|
|
34
|
+
} = require("../util/identifier");
|
|
26
35
|
const implicitTypeLoaderFallback = require("../util/implicitTypeLoaderFallback");
|
|
27
36
|
const lazyModule = require("../util/lazyModule");
|
|
28
37
|
const memoize = require("../util/memoize");
|
|
@@ -31,7 +40,7 @@ const preloadModuleType = require("../util/preloadModuleType");
|
|
|
31
40
|
const {
|
|
32
41
|
PUBLIC_PATH_AUTO: autoPlaceholder
|
|
33
42
|
} = require("../util/publicPathPlaceholder");
|
|
34
|
-
const
|
|
43
|
+
const { removeBOMFromResult } = require("../util/removeBOM");
|
|
35
44
|
const HtmlModule = require("./HtmlModule");
|
|
36
45
|
|
|
37
46
|
const getMimeTypes = memoize(() => require("../util/mimeTypes"));
|
|
@@ -45,20 +54,41 @@ const getHtmlParser = lazyModule(() => require("./HtmlParser"));
|
|
|
45
54
|
// html generation only happens once a build actually has an html module
|
|
46
55
|
const getHtmlGenerator = memoize(() => require("./HtmlGenerator"));
|
|
47
56
|
|
|
57
|
+
// only reached once a page names a CSS chunk of its own
|
|
58
|
+
const getCssModulesPlugin = memoize(() => require("../css/CssModulesPlugin"));
|
|
59
|
+
|
|
48
60
|
/**
|
|
49
61
|
* @import {
|
|
50
62
|
* EntryDescriptionNormalized,
|
|
63
|
+
* FilenameTemplate,
|
|
51
64
|
* OutputHtmlOptions,
|
|
52
65
|
* HtmlFaviconIcon
|
|
53
66
|
* } from "../../declarations/WebpackOptions"
|
|
54
67
|
*/
|
|
68
|
+
/**
|
|
69
|
+
* @import {
|
|
70
|
+
* OutputNormalizedWithDefaults as OutputOptions
|
|
71
|
+
* } from "../config/defaults"
|
|
72
|
+
*/
|
|
55
73
|
/** @typedef {import("../../declarations/WebpackOptions").OutputHtmlOptions["favicon"]} FaviconOption */
|
|
56
74
|
/** @typedef {import("../../declarations/WebpackOptions").OutputHtmlOptions["manifest"]} ManifestOption */
|
|
57
75
|
/** @typedef {Exclude<HtmlFaviconIcon, string>} FaviconIcon */
|
|
76
|
+
/** @import Chunk, { ChunkFilenameTemplate } from "../Chunk" */
|
|
77
|
+
/** @import ChunkGraph from "../ChunkGraph" */
|
|
58
78
|
/** @import Compiler from "../Compiler" */
|
|
79
|
+
/** @import Module from "../Module" */
|
|
80
|
+
/** @typedef {import("../Compilation").EntryData} EntryData */
|
|
59
81
|
/** @import { HtmlModuleBuildInfo } from "./HtmlModule" */
|
|
60
82
|
/** @import HtmlParser from "./HtmlParser" */
|
|
61
|
-
/** @typedef {{ request: string, entryName: string, type: "script" | "script-module" | "modulepreload" | "stylesheet" | "html" | "preload" | "prefetch", css?: boolean }} HtmlEntryInfo */
|
|
83
|
+
/** @typedef {{ request: string, entryName: string, index: number, type: "script" | "script-module" | "modulepreload" | "stylesheet" | "html" | "preload" | "prefetch", css?: boolean }} HtmlEntryInfo */
|
|
84
|
+
/**
|
|
85
|
+
* What one extracted entry needs to be named. Recorded in page order once
|
|
86
|
+
* every page is built, and resolved to filenames once chunks exist.
|
|
87
|
+
* @typedef {object} PendingName
|
|
88
|
+
* @property {string} base name the tag's url (or its page) asks for, before numbering
|
|
89
|
+
* @property {FilenameTemplate} jsTemplate `output.filename` for this entry, as configured
|
|
90
|
+
* @property {string=} freeName name of a page-only entry, which emits nothing and leaves it free
|
|
91
|
+
*/
|
|
62
92
|
|
|
63
93
|
/** @typedef {{ outputName: string }} HtmlTransformHtmlContext */
|
|
64
94
|
/** @typedef {{ outputName: string }} HtmlEmittedContext */
|
|
@@ -118,10 +148,9 @@ const createCompilationHooks = () => ({
|
|
|
118
148
|
|
|
119
149
|
const PLUGIN_NAME = "HtmlModulesPlugin";
|
|
120
150
|
|
|
121
|
-
// Built-in default favicon
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// Resolved from `__filename` (a sibling of this module) — no `path` needed.
|
|
151
|
+
// Built-in default favicon, referenced as a `file:` request so the wrapper's
|
|
152
|
+
// `<link rel="icon">` flows through the normal asset pipeline: emitted hashed,
|
|
153
|
+
// with the right publicPath and no direct IO.
|
|
125
154
|
const DEFAULT_FAVICON = new URL("./favicon.svg", pathToFileURL(__filename))
|
|
126
155
|
.href;
|
|
127
156
|
|
|
@@ -222,6 +251,130 @@ const isIntegrityEnabled = (integrity) =>
|
|
|
222
251
|
// `\.html`/`\.css` request matchers for the synthetic `output.html` wrapper.
|
|
223
252
|
const HTML_REQUEST_RE = /\.html(\?|$)/i;
|
|
224
253
|
const CSS_REQUEST_RE = /\.css(\?|$)/i;
|
|
254
|
+
/**
|
|
255
|
+
* The entry a page is the whole of: nothing imports the module and the entry
|
|
256
|
+
* asks for nothing else, so the entry's JavaScript would be the page itself.
|
|
257
|
+
* @param {Compilation} compilation compilation
|
|
258
|
+
* @param {Module} module html module
|
|
259
|
+
* @returns {{ name: string, data: EntryData } | undefined} the page's own entry, when it has one
|
|
260
|
+
*/
|
|
261
|
+
const getPageEntry = (compilation, module) => {
|
|
262
|
+
const { moduleGraph } = compilation;
|
|
263
|
+
for (const connection of moduleGraph.getIncomingConnections(module)) {
|
|
264
|
+
if (connection.originModule) return undefined;
|
|
265
|
+
}
|
|
266
|
+
for (const [name, data] of compilation.entries) {
|
|
267
|
+
if (data.dependencies.length !== 1) continue;
|
|
268
|
+
if (data.includeDependencies.length !== 0) continue;
|
|
269
|
+
if (moduleGraph.getModule(data.dependencies[0]) === module) {
|
|
270
|
+
return { name, data };
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* The entry of a page that emits nothing but its markup, so its chunk carries
|
|
278
|
+
* no JavaScript. An `output.library` asks for the page's exports, and keeps it.
|
|
279
|
+
* @param {Compilation} compilation compilation
|
|
280
|
+
* @param {Module} module html module
|
|
281
|
+
* @returns {{ name: string, data: EntryData } | undefined} the entry, when the page is all it emits
|
|
282
|
+
*/
|
|
283
|
+
const getPageOnlyEntry = (compilation, module) => {
|
|
284
|
+
const entry = getPageEntry(compilation, module);
|
|
285
|
+
if (entry === undefined) return undefined;
|
|
286
|
+
const { library } = entry.data.options;
|
|
287
|
+
const configured =
|
|
288
|
+
library === undefined ? compilation.outputOptions.library : library;
|
|
289
|
+
return configured === undefined ? entry : undefined;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* The basename a tag's url lends to the entry it becomes, so
|
|
294
|
+
* `src="./my-script.js"` emits `my-script.js`. Undefined for an inline body.
|
|
295
|
+
* @param {string} request the tag's request
|
|
296
|
+
* @returns {string | undefined} the basename, when the url carries one
|
|
297
|
+
*/
|
|
298
|
+
const getRequestBaseName = (request) => {
|
|
299
|
+
// An inline `<script>` body is a `data:` request webpack writes itself.
|
|
300
|
+
if (request.startsWith("data:")) return undefined;
|
|
301
|
+
const { path: file } = parseResource(request);
|
|
302
|
+
return basename(file, extname(file)) || undefined;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Claims `base`, numbering it while something else already emits under that
|
|
307
|
+
* name, so two tags sharing a basename stay distinct.
|
|
308
|
+
* @param {string} base preferred name
|
|
309
|
+
* @param {Set<string>} taken names this kind of output already emits under
|
|
310
|
+
* @returns {string} the claimed name
|
|
311
|
+
*/
|
|
312
|
+
const claimName = (base, taken) => {
|
|
313
|
+
let name = base;
|
|
314
|
+
for (let index = 1; taken.has(name); index++) name = `${base}${index}`;
|
|
315
|
+
taken.add(name);
|
|
316
|
+
return name;
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// Placeholders that tell chunks apart on their own, so a template carrying
|
|
320
|
+
// one needs no `[name]`. Not `[id]`: an extracted entry's id is synthetic.
|
|
321
|
+
const CONTENT_PLACEHOLDER_REGEXP =
|
|
322
|
+
/\[(?:chunkhash|contenthash|fullhash|hash)[\]:]/;
|
|
323
|
+
|
|
324
|
+
// Basename stem of a filename template — what `[name]` stands in for, keeping
|
|
325
|
+
// the directory, extension and query the template asked for.
|
|
326
|
+
const TEMPLATE_STEM_REGEXP = /(^|\/)[^/?]*?((?:\.[^./?]+)*)(\?.*)?$/;
|
|
327
|
+
|
|
328
|
+
const NAME_PLACEHOLDER_REGEXP = /\[name\]/g;
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* A filename template usable for a page's extracted entries: it must tell one
|
|
332
|
+
* entry from another, or every entry of the page would be emitted to the same
|
|
333
|
+
* file. A template naming neither the chunk nor its content lends its directory
|
|
334
|
+
* and extension to a `[name]` instead.
|
|
335
|
+
* @param {string} template configured template
|
|
336
|
+
* @param {string} extension extension to fall back to when the template names none
|
|
337
|
+
* @returns {string} a template that tells the page's entries apart
|
|
338
|
+
*/
|
|
339
|
+
const getNamedTemplate = (template, extension) => {
|
|
340
|
+
if (
|
|
341
|
+
template.includes("[name]") ||
|
|
342
|
+
CONTENT_PLACEHOLDER_REGEXP.test(template)
|
|
343
|
+
) {
|
|
344
|
+
return template;
|
|
345
|
+
}
|
|
346
|
+
return template.replace(
|
|
347
|
+
TEMPLATE_STEM_REGEXP,
|
|
348
|
+
(_, dir, ext, query) => `${dir}[name]${ext || extension}${query || ""}`
|
|
349
|
+
);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* The filename one extracted entry emits under, with `name` filling the
|
|
354
|
+
* `[name]` its template carries or the stem it leaves behind.
|
|
355
|
+
* @param {string} template configured template
|
|
356
|
+
* @param {string} extension extension to fall back to when the template names none
|
|
357
|
+
* @param {string} name the name this entry claimed
|
|
358
|
+
* @returns {string} the entry's filename template
|
|
359
|
+
*/
|
|
360
|
+
const fillNamedTemplate = (template, extension, name) =>
|
|
361
|
+
getNamedTemplate(template, extension).replace(NAME_PLACEHOLDER_REGEXP, name);
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* The same, for a template `output.filename` states as a function: it is called
|
|
365
|
+
* at emit, and the path it returns read for a stem the same way.
|
|
366
|
+
* @param {FilenameTemplate} template configured template
|
|
367
|
+
* @param {string} extension extension to fall back to when the template names none
|
|
368
|
+
* @param {string} name the name this entry claimed
|
|
369
|
+
* @returns {ChunkFilenameTemplate} the entry's filename template
|
|
370
|
+
*/
|
|
371
|
+
const getEntryTemplate = (template, extension, name) => {
|
|
372
|
+
if (typeof template === "function") {
|
|
373
|
+
return (pathData, assetInfo) =>
|
|
374
|
+
fillNamedTemplate(template(pathData, assetInfo), extension, name);
|
|
375
|
+
}
|
|
376
|
+
return fillNamedTemplate(template, extension, name);
|
|
377
|
+
};
|
|
225
378
|
|
|
226
379
|
/**
|
|
227
380
|
* Requests an `output.html` page must load for an entry: its `dependOn`
|
|
@@ -238,7 +391,12 @@ const collectHtmlEntryRequests = (name, entries) => {
|
|
|
238
391
|
const seenRequests = new Set();
|
|
239
392
|
/** @type {Set<string>} */
|
|
240
393
|
const visited = new Set();
|
|
241
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Collects an entry's non-html requests, `dependOn` entries included.
|
|
396
|
+
* @param {string} entryName entry to walk
|
|
397
|
+
* @returns {void}
|
|
398
|
+
*/
|
|
399
|
+
const walk = (entryName) => {
|
|
242
400
|
if (visited.has(entryName)) return;
|
|
243
401
|
visited.add(entryName);
|
|
244
402
|
const desc = entries[entryName];
|
|
@@ -286,7 +444,7 @@ class HtmlModulesPlugin {
|
|
|
286
444
|
* digest of `content`, with `nonNumericOnlyHash` applied — webpack's
|
|
287
445
|
* standard `[contenthash]` recipe.
|
|
288
446
|
* @param {string | Buffer} content content to hash
|
|
289
|
-
* @param {
|
|
447
|
+
* @param {OutputOptions} outputOptions output options
|
|
290
448
|
* @returns {string} content hash
|
|
291
449
|
*/
|
|
292
450
|
static computeContentHash(content, outputOptions) {
|
|
@@ -308,7 +466,7 @@ class HtmlModulesPlugin {
|
|
|
308
466
|
* initial chunks, `output.htmlChunkFilename` otherwise — the HTML counterpart
|
|
309
467
|
* of `CssModulesPlugin.getChunkFilenameTemplate`.
|
|
310
468
|
* @param {import("../Chunk")} chunk chunk
|
|
311
|
-
* @param {
|
|
469
|
+
* @param {OutputOptions} outputOptions output options
|
|
312
470
|
* @returns {import("../Chunk").ChunkFilenameTemplate} used filename template
|
|
313
471
|
*/
|
|
314
472
|
static getChunkFilenameTemplate(chunk, outputOptions) {
|
|
@@ -347,10 +505,9 @@ class HtmlModulesPlugin {
|
|
|
347
505
|
// several entries, so those can only be applied per emitted asset.
|
|
348
506
|
/** @type {Map<string, OutputHtmlOptions>} */
|
|
349
507
|
const htmlOptionsByEntry = new Map();
|
|
350
|
-
// SRI sentinels are emitted
|
|
351
|
-
//
|
|
352
|
-
//
|
|
353
|
-
// `.html` pages never reach the entry hook, hence the global seed.
|
|
508
|
+
// SRI sentinels are emitted before the owning entry is known, so one page
|
|
509
|
+
// asking for integrity turns them on for all and the rest drop them on emit.
|
|
510
|
+
// Authored `.html` pages never reach the entry hook, hence the global seed.
|
|
354
511
|
let anyIntegrity = isIntegrityEnabled(
|
|
355
512
|
globalHtmlOptions && globalHtmlOptions.integrity
|
|
356
513
|
);
|
|
@@ -383,13 +540,9 @@ class HtmlModulesPlugin {
|
|
|
383
540
|
return options;
|
|
384
541
|
};
|
|
385
542
|
|
|
386
|
-
// `output.html`
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
// injected first so the page loads the shared/runtime chunks before
|
|
390
|
-
// the entry's own (see `collectHtmlEntryRequests`). `crossOriginLoading`
|
|
391
|
-
// and SRI are applied to the injected tags centrally in
|
|
392
|
-
// HtmlEntryDependency.
|
|
543
|
+
// `output.html` wraps a non-HTML entry in a synthetic HTML module, so the
|
|
544
|
+
// existing pipeline injects its chunks. `dependOn` ancestors go first, so the
|
|
545
|
+
// page loads shared and runtime chunks before the entry's own.
|
|
393
546
|
EntryOptionPlugin.getHooks(compiler).entry.tap(
|
|
394
547
|
PLUGIN_NAME,
|
|
395
548
|
(context, name, desc) => {
|
|
@@ -464,24 +617,20 @@ class HtmlModulesPlugin {
|
|
|
464
617
|
/** @type {Map<string, { content: string, source: import("webpack-sources").RawSource }>} */
|
|
465
618
|
const sentinelResolvedSourceCache = new Map();
|
|
466
619
|
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
// and
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
//
|
|
476
|
-
|
|
477
|
-
// `finishMake` creates their entries without scanning the whole module
|
|
478
|
-
// graph), the stylesheet entry names (read in `afterChunks`) and the html
|
|
479
|
-
// options of every emitted page, keyed by its asset name.
|
|
480
|
-
/** @type {WeakMap<import("../Compilation"), { htmlModules: Set<import("../Module")>, stylesheetEntries: Set<string>, htmlAssetOptions: Map<string, OutputHtmlOptions> }>} */
|
|
620
|
+
// WHY: the `script` and `script-module` groups are chained through a
|
|
621
|
+
// leader-only `dependOn`, so they share a runtime: the group's first entry
|
|
622
|
+
// owns it and every later one sets `dependOn: [leader]`. A modulepreload
|
|
623
|
+
// entry is emitted independently, with no `dependOn`, so a later script can
|
|
624
|
+
// never import it as a runtime leader — which is what keeps the "preload but
|
|
625
|
+
// don't execute" contract of `<link rel="modulepreload">` intact.
|
|
626
|
+
// Per-compilation state: the HTML modules seen during make, so `finishMake`
|
|
627
|
+
// creates their entries without scanning the module graph, plus the
|
|
628
|
+
// stylesheet entry names and each emitted page's html options.
|
|
629
|
+
/** @type {WeakMap<import("../Compilation"), { htmlModules: Set<Module>, stylesheetEntries: Set<string>, pendingNames: Map<string, PendingName>, htmlAssetOptions: Map<string, OutputHtmlOptions> }>} */
|
|
481
630
|
const compilationState = new WeakMap();
|
|
482
631
|
/**
|
|
483
632
|
* @param {import("../Compilation")} compilation compilation
|
|
484
|
-
* @returns {{ htmlModules: Set<
|
|
633
|
+
* @returns {{ htmlModules: Set<Module>, stylesheetEntries: Set<string>, pendingNames: Map<string, PendingName>, htmlAssetOptions: Map<string, OutputHtmlOptions> }} per-compilation state
|
|
485
634
|
*/
|
|
486
635
|
const getState = (compilation) => {
|
|
487
636
|
let state = compilationState.get(compilation);
|
|
@@ -489,6 +638,7 @@ class HtmlModulesPlugin {
|
|
|
489
638
|
state = {
|
|
490
639
|
htmlModules: new Set(),
|
|
491
640
|
stylesheetEntries: new Set(),
|
|
641
|
+
pendingNames: new Map(),
|
|
492
642
|
htmlAssetOptions: new Map()
|
|
493
643
|
};
|
|
494
644
|
compilationState.set(compilation, state);
|
|
@@ -496,14 +646,19 @@ class HtmlModulesPlugin {
|
|
|
496
646
|
return state;
|
|
497
647
|
};
|
|
498
648
|
compiler.hooks.finishMake.tapAsync(PLUGIN_NAME, (compilation, callback) => {
|
|
499
|
-
const { htmlModules, stylesheetEntries } =
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
//
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
|
|
649
|
+
const { htmlModules, stylesheetEntries, pendingNames } =
|
|
650
|
+
getState(compilation);
|
|
651
|
+
/** @type {Set<string>} */
|
|
652
|
+
const extractedNames = new Set();
|
|
653
|
+
// The page each `type: "html"` link built, so the naming walk below can
|
|
654
|
+
// follow the links in document order instead of in build order.
|
|
655
|
+
/** @type {Map<string, Module>} */
|
|
656
|
+
const linkedPages = new Map();
|
|
657
|
+
|
|
658
|
+
// Collect the entries an HTML module asks for. Only the script chains share
|
|
659
|
+
// a runtime, through a leader-only `dependOn`; chaining a CSS or page entry
|
|
660
|
+
// into a JS leader would mix unrelated outputs into one chunk.
|
|
661
|
+
/** @type {(module: Module) => { context: string, request: string, name: string, dependOn: string[] | undefined }[]} */
|
|
507
662
|
const collectEntrySpecs = (module) => {
|
|
508
663
|
const { htmlEntries } = /** @type {HtmlModuleBuildInfo} */ (
|
|
509
664
|
module.buildInfo
|
|
@@ -525,10 +680,11 @@ class HtmlModulesPlugin {
|
|
|
525
680
|
leaderName = entry.entryName;
|
|
526
681
|
}
|
|
527
682
|
// Stylesheet entries and `as="style"` preload/prefetch entries emit
|
|
528
|
-
// a CSS chunk, so they
|
|
529
|
-
if (groupKind === "stylesheet" || entry.css) {
|
|
683
|
+
// a CSS chunk, so they are named from `output.cssFilename` alone.
|
|
684
|
+
if (groupKind === "stylesheet" || Boolean(entry.css)) {
|
|
530
685
|
stylesheetEntries.add(entry.entryName);
|
|
531
686
|
}
|
|
687
|
+
extractedNames.add(entry.entryName);
|
|
532
688
|
specs.push({
|
|
533
689
|
context,
|
|
534
690
|
request: entry.request,
|
|
@@ -540,9 +696,70 @@ class HtmlModulesPlugin {
|
|
|
540
696
|
return specs;
|
|
541
697
|
};
|
|
542
698
|
|
|
699
|
+
// Records what a page's entries ask to be named, then walks its links —
|
|
700
|
+
// once every page is built, so the order is the documents', not the builds'.
|
|
701
|
+
/** @type {(module: Module, seen: Set<Module>) => void} */
|
|
702
|
+
const recordNames = (module, seen) => {
|
|
703
|
+
if (seen.has(module)) return;
|
|
704
|
+
seen.add(module);
|
|
705
|
+
const { htmlEntries } = /** @type {HtmlModuleBuildInfo} */ (
|
|
706
|
+
module.buildInfo
|
|
707
|
+
);
|
|
708
|
+
if (!htmlEntries) return;
|
|
709
|
+
const pageEntry = getPageOnlyEntry(compilation, module);
|
|
710
|
+
const namedEntry =
|
|
711
|
+
pageEntry !== undefined && !extractedNames.has(pageEntry.name)
|
|
712
|
+
? pageEntry
|
|
713
|
+
: undefined;
|
|
714
|
+
const { resource } = /** @type {NormalModule} */ (module);
|
|
715
|
+
// An `output.html` page is a wrapper webpack writes around an entry, so
|
|
716
|
+
// what it loads is that entry's own output and takes its name.
|
|
717
|
+
const wrapsEntry =
|
|
718
|
+
namedEntry !== undefined &&
|
|
719
|
+
typeof resource === "string" &&
|
|
720
|
+
resource.startsWith("data:text/html");
|
|
721
|
+
const { filename } = compilation.outputOptions;
|
|
722
|
+
// Kept as configured, a function included, and read for a name once the
|
|
723
|
+
// chunks exist.
|
|
724
|
+
const jsTemplate =
|
|
725
|
+
namedEntry && namedEntry.data.options.filename !== undefined
|
|
726
|
+
? namedEntry.data.options.filename
|
|
727
|
+
: filename;
|
|
728
|
+
// In document order, so of two tags sharing a basename the first a
|
|
729
|
+
// reader sees keeps it. A linked page is named on emit instead.
|
|
730
|
+
/** @type {HtmlEntryInfo[]} */
|
|
731
|
+
const ordered = [];
|
|
732
|
+
/** @type {HtmlEntryInfo[]} */
|
|
733
|
+
const links = [];
|
|
734
|
+
for (const [groupKind, group] of Object.entries(htmlEntries)) {
|
|
735
|
+
for (const entry of group) {
|
|
736
|
+
(groupKind === "html" ? links : ordered).push(entry);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
ordered.sort((a, b) => a.index - b.index);
|
|
740
|
+
for (const entry of ordered) {
|
|
741
|
+
// An inline `<script>` body has no url to be named after, so it
|
|
742
|
+
// keeps the name of its own entry, page hash and tag index.
|
|
743
|
+
const base =
|
|
744
|
+
wrapsEntry && namedEntry
|
|
745
|
+
? namedEntry.name
|
|
746
|
+
: getRequestBaseName(entry.request) || entry.entryName;
|
|
747
|
+
pendingNames.set(entry.entryName, {
|
|
748
|
+
base,
|
|
749
|
+
jsTemplate,
|
|
750
|
+
freeName: namedEntry && namedEntry.name
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
links.sort((a, b) => a.index - b.index);
|
|
754
|
+
for (const link of links) {
|
|
755
|
+
const page = linkedPages.get(link.entryName);
|
|
756
|
+
if (page) recordNames(page, seen);
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
|
|
543
760
|
// Push one collected reference as a compilation entry; resolves with
|
|
544
761
|
// the built entry module.
|
|
545
|
-
/** @type {(spec: { context: string, request: string, name: string, dependOn: string[] | undefined }) => Promise<
|
|
762
|
+
/** @type {(spec: { context: string, request: string, name: string, dependOn: string[] | undefined }) => Promise<Module | null>} */
|
|
546
763
|
const addEntry = (spec) =>
|
|
547
764
|
new Promise((resolve, reject) => {
|
|
548
765
|
compilation.addEntry(
|
|
@@ -550,10 +767,8 @@ class HtmlModulesPlugin {
|
|
|
550
767
|
EntryPlugin.createDependency(spec.request, { name: spec.name }),
|
|
551
768
|
{
|
|
552
769
|
name: spec.name,
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
// `.css` name via `cssFilenameTemplate` below; `html` page entries
|
|
556
|
-
// emit their file via `renderManifest`.
|
|
770
|
+
// A placeholder `afterChunks` overwrites for every entry it
|
|
771
|
+
// names; only a linked page keeps it, and it emits no JavaScript.
|
|
557
772
|
filename: compilation.outputOptions.chunkFilename || "[name].js",
|
|
558
773
|
dependOn: spec.dependOn
|
|
559
774
|
},
|
|
@@ -567,7 +782,7 @@ class HtmlModulesPlugin {
|
|
|
567
782
|
// every HTML entry already gets. `processed` guards diamonds and cycles.
|
|
568
783
|
/** @type {WeakSet<import("../Module")>} */
|
|
569
784
|
const processed = new WeakSet();
|
|
570
|
-
/** @type {(module:
|
|
785
|
+
/** @type {(module: Module) => Promise<void>} */
|
|
571
786
|
const processEntry = async (module) => {
|
|
572
787
|
if (processed.has(module)) return;
|
|
573
788
|
processed.add(module);
|
|
@@ -575,27 +790,30 @@ class HtmlModulesPlugin {
|
|
|
575
790
|
collectEntrySpecs(module).map(async (spec) => {
|
|
576
791
|
const entryModule = await addEntry(spec);
|
|
577
792
|
if (entryModule && entryModule.type === HTML_MODULE_TYPE) {
|
|
793
|
+
linkedPages.set(spec.name, entryModule);
|
|
578
794
|
await processEntry(entryModule);
|
|
579
795
|
}
|
|
580
796
|
})
|
|
581
797
|
);
|
|
582
798
|
};
|
|
583
|
-
// Seed with the HTML modules seen during make
|
|
584
|
-
//
|
|
585
|
-
//
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
799
|
+
// Seed with the HTML modules seen during make; linked pages are reached by
|
|
800
|
+
// the recursion above. Sorted because they are tracked in build-completion
|
|
801
|
+
// order, which the generated names must not depend on.
|
|
802
|
+
const seeds = [...htmlModules].sort(compareModulesByIdentifier);
|
|
803
|
+
Promise.all(seeds.map(processEntry)).then(() => {
|
|
804
|
+
/** @type {Set<Module>} */
|
|
805
|
+
const named = new Set();
|
|
806
|
+
for (const seed of seeds) recordNames(seed, named);
|
|
807
|
+
callback();
|
|
808
|
+
}, callback);
|
|
590
809
|
});
|
|
591
810
|
|
|
592
811
|
// `csp` injects a `<meta http-equiv="Content-Security-Policy">` and
|
|
593
|
-
// `integrity` resolves the SRI sentinels
|
|
594
|
-
// content is final
|
|
595
|
-
|
|
596
|
-
// `"auto"` marks implicit enablement
|
|
597
|
-
//
|
|
598
|
-
// (e.g. html-webpack-plugin's template loader in its child compiler).
|
|
812
|
+
// `integrity` resolves the SRI sentinels, both per page once its inline
|
|
813
|
+
// content is final, so an entry's `html` can override them.
|
|
814
|
+
|
|
815
|
+
// `"auto"` marks implicit enablement, the one case where loaders win over
|
|
816
|
+
// the built-in type — see `applyExperimentsDefaults`.
|
|
599
817
|
// TODO webpack 6: html defaults to `true`, drop this implicit-only fallback.
|
|
600
818
|
const implicitlyEnabled = compiler.options.experiments.html === "auto";
|
|
601
819
|
compiler.hooks.compilation.tap(
|
|
@@ -610,12 +828,13 @@ class HtmlModulesPlugin {
|
|
|
610
828
|
);
|
|
611
829
|
}
|
|
612
830
|
const { htmlModules } = getState(compilation);
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
831
|
+
/**
|
|
832
|
+
* Records HTML modules as they are built or restored, so `finishMake`
|
|
833
|
+
* creates their entries without scanning the whole module graph.
|
|
834
|
+
* @param {import("../Module")} module built or restored module
|
|
835
|
+
* @returns {void}
|
|
836
|
+
*/
|
|
837
|
+
const trackHtmlModule = (module) => {
|
|
619
838
|
if (module.type !== HTML_MODULE_TYPE) return;
|
|
620
839
|
// enabled here, not on the compilation hook: an integrity build
|
|
621
840
|
// with no html module must not load the generator
|
|
@@ -627,13 +846,12 @@ class HtmlModulesPlugin {
|
|
|
627
846
|
compilation.hooks.succeedModule.tap(PLUGIN_NAME, trackHtmlModule);
|
|
628
847
|
compilation.hooks.stillValidModule.tap(PLUGIN_NAME, trackHtmlModule);
|
|
629
848
|
|
|
630
|
-
// Resolve integrity and inline sentinels after `RealContentHashPlugin
|
|
631
|
-
// so final bytes are in place. Only HTML pages carry
|
|
632
|
-
|
|
633
|
-
// SRI
|
|
634
|
-
//
|
|
635
|
-
//
|
|
636
|
-
// so a CDN deployment doesn't ship no-op integrity attributes.
|
|
849
|
+
// Resolve integrity and inline sentinels after `RealContentHashPlugin`,
|
|
850
|
+
// so final bytes are in place. Only HTML pages carry them.
|
|
851
|
+
|
|
852
|
+
// SRI takes effect only on a cross-origin subresource fetched with CORS,
|
|
853
|
+
// so without `output.crossOriginLoading` the browser ignores `integrity`.
|
|
854
|
+
// Warn once, rather than let a CDN deployment ship no-op attributes.
|
|
637
855
|
if (anyIntegrity && !compilation.outputOptions.crossOriginLoading) {
|
|
638
856
|
compilation.warnings.push(
|
|
639
857
|
new WebpackError(
|
|
@@ -679,12 +897,9 @@ class HtmlModulesPlugin {
|
|
|
679
897
|
inlinedFiles
|
|
680
898
|
);
|
|
681
899
|
}
|
|
682
|
-
// `injectTags
|
|
683
|
-
//
|
|
684
|
-
//
|
|
685
|
-
// render every edit — placement, attribute rewrites, moves,
|
|
686
|
-
// removals, CSP hashes/nonce/meta — in one pass. Injected inline
|
|
687
|
-
// `<script>`/`<style>` are hashed like the page's own.
|
|
900
|
+
// `injectTags`, `transformTags` and CSP all run over a single parse:
|
|
901
|
+
// collect the tags and anchors once, let the hooks act, then render
|
|
902
|
+
// every edit in one pass.
|
|
688
903
|
const injected = await hooks.injectTags.promise([], {
|
|
689
904
|
outputName: name,
|
|
690
905
|
html: resolved
|
|
@@ -714,73 +929,114 @@ class HtmlModulesPlugin {
|
|
|
714
929
|
// An inlined chunk file is dead weight once nothing else references
|
|
715
930
|
// it by URL (another page's tag, or the runtime's async chunk map);
|
|
716
931
|
// a content-hashed filename makes a substring hit a real reference.
|
|
932
|
+
/** @type {Set<string>} */
|
|
933
|
+
const deletionCandidates = new Set(inlinedFiles);
|
|
717
934
|
// Materialize each other asset's source once (it can be expensive to
|
|
718
|
-
// render) and test all
|
|
719
|
-
// re-materializing every asset per
|
|
720
|
-
if (
|
|
935
|
+
// render) and test all candidates against it, rather than
|
|
936
|
+
// re-materializing every asset per candidate.
|
|
937
|
+
if (deletionCandidates.size > 0) {
|
|
721
938
|
/** @type {Set<string>} */
|
|
722
939
|
const stillReferenced = new Set();
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
}
|
|
940
|
+
/** @type {string[]} */
|
|
941
|
+
const pending = [];
|
|
942
|
+
/**
|
|
943
|
+
* @param {string} name asset whose source may name a candidate
|
|
944
|
+
*/
|
|
945
|
+
const markReferenced = (name) => {
|
|
730
946
|
const source = compilation.assets[name].source();
|
|
731
|
-
if (typeof source !== "string")
|
|
732
|
-
for (const file of
|
|
947
|
+
if (typeof source !== "string") return;
|
|
948
|
+
for (const file of deletionCandidates) {
|
|
733
949
|
if (!stillReferenced.has(file) && source.includes(file)) {
|
|
734
950
|
stillReferenced.add(file);
|
|
951
|
+
pending.push(file);
|
|
735
952
|
}
|
|
736
953
|
}
|
|
954
|
+
};
|
|
955
|
+
for (const name of Object.keys(compilation.assets)) {
|
|
956
|
+
if (
|
|
957
|
+
deletionCandidates.has(name) ||
|
|
958
|
+
stillReferenced.size === deletionCandidates.size
|
|
959
|
+
) {
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
markReferenced(name);
|
|
737
963
|
}
|
|
738
|
-
|
|
964
|
+
// A kept candidate can reference another through its async chunk
|
|
965
|
+
// map, so follow each until nothing new is kept.
|
|
966
|
+
while (pending.length > 0) {
|
|
967
|
+
markReferenced(/** @type {string} */ (pending.pop()));
|
|
968
|
+
}
|
|
969
|
+
for (const file of deletionCandidates) {
|
|
739
970
|
if (!stillReferenced.has(file)) compilation.deleteAsset(file);
|
|
740
971
|
}
|
|
741
972
|
}
|
|
742
973
|
}
|
|
743
974
|
);
|
|
744
975
|
|
|
745
|
-
//
|
|
746
|
-
//
|
|
747
|
-
//
|
|
748
|
-
// Compilation only flows `options.filename` to `chunk.filenameTemplate`,
|
|
749
|
-
// which controls JS emit — there's no entry-level `cssFilename`.
|
|
750
|
-
// Set it ourselves after chunks are created so each stylesheet
|
|
751
|
-
// entry emits to a distinct file derived from `output.cssFilename`
|
|
752
|
-
// (or `output.cssChunkFilename` for non-initial CSS chunks).
|
|
976
|
+
// There is no entry-level `cssFilename`: Compilation flows
|
|
977
|
+
// `options.filename` only to `chunk.filenameTemplate`, which drives JS
|
|
978
|
+
// emit. So set `chunk.cssFilenameTemplate` here, once chunks exist.
|
|
753
979
|
compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
|
|
754
|
-
const { stylesheetEntries } = getState(compilation);
|
|
755
|
-
if (
|
|
756
|
-
|
|
980
|
+
const { stylesheetEntries, pendingNames } = getState(compilation);
|
|
981
|
+
if (pendingNames.size === 0) return;
|
|
982
|
+
const { chunkGraph, outputOptions } = compilation;
|
|
983
|
+
const jsExtension = outputOptions.module ? ".mjs" : ".js";
|
|
984
|
+
// Claimed in the order the pages recorded them, which is the
|
|
985
|
+
// documents' order rather than their builds'.
|
|
986
|
+
const takenJsNames = new Set(compilation.entries.keys());
|
|
987
|
+
const takenCssNames = new Set(takenJsNames);
|
|
988
|
+
// An extracted entry emits nothing under its own synthetic name, so
|
|
989
|
+
// that name never stands in the way of the one its tag asks for.
|
|
990
|
+
for (const entryName of pendingNames.keys()) {
|
|
991
|
+
takenJsNames.delete(entryName);
|
|
992
|
+
takenCssNames.delete(entryName);
|
|
993
|
+
}
|
|
994
|
+
for (const { freeName } of pendingNames.values()) {
|
|
995
|
+
if (freeName === undefined) continue;
|
|
996
|
+
// A page-only entry emits nothing of its own, so its name is free for
|
|
997
|
+
// the entries extracted from it — `app.html` keeps `app.js`.
|
|
998
|
+
takenJsNames.delete(freeName);
|
|
999
|
+
takenCssNames.delete(freeName);
|
|
1000
|
+
}
|
|
1001
|
+
for (const [entryName, { base, jsTemplate }] of pendingNames) {
|
|
757
1002
|
const entrypoint = compilation.entrypoints.get(entryName);
|
|
758
1003
|
if (!entrypoint) continue;
|
|
759
1004
|
const chunk = entrypoint.getEntrypointChunk();
|
|
760
1005
|
if (!chunk) continue;
|
|
761
|
-
//
|
|
762
|
-
//
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
1006
|
+
// A stylesheet entry emits no JavaScript, so it claims no JS name and
|
|
1007
|
+
// leaves that one to a `<script src>` of the same basename.
|
|
1008
|
+
const emitsCss = stylesheetEntries.has(entryName);
|
|
1009
|
+
if (!emitsCss) {
|
|
1010
|
+
// `output.filename` named after the tag's url, the way an entry
|
|
1011
|
+
// point is named. `Compilation` set it from the placeholder above.
|
|
1012
|
+
chunk.filenameTemplate = getEntryTemplate(
|
|
1013
|
+
jsTemplate,
|
|
1014
|
+
jsExtension,
|
|
1015
|
+
claimName(base, takenJsNames)
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
// A `<script src>` whose chunk carries no CSS claims no CSS name, so
|
|
1019
|
+
// a `<link>` of the same basename still gets the plain one.
|
|
1020
|
+
if (
|
|
1021
|
+
!emitsCss &&
|
|
1022
|
+
!getCssModulesPlugin().chunkHasCss(chunk, chunkGraph)
|
|
1023
|
+
) {
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
chunk.cssFilenameTemplate = getEntryTemplate(
|
|
1027
|
+
outputOptions.cssFilename,
|
|
1028
|
+
".css",
|
|
1029
|
+
claimName(base, takenCssNames)
|
|
1030
|
+
);
|
|
774
1031
|
}
|
|
775
1032
|
});
|
|
776
1033
|
compilation.dependencyTemplates.set(
|
|
777
1034
|
StaticExportsDependency,
|
|
778
1035
|
new StaticExportsDependency.Template()
|
|
779
1036
|
);
|
|
780
|
-
// `ConstDependency`
|
|
781
|
-
// `
|
|
782
|
-
//
|
|
783
|
-
// generator runs the insertion.
|
|
1037
|
+
// HtmlParser uses `ConstDependency` to insert ` type="module"` into a
|
|
1038
|
+
// rewritten `<script>` under `output.module`; its template has to be
|
|
1039
|
+
// registered for the HTML generator to run that insertion.
|
|
784
1040
|
compilation.dependencyTemplates.set(
|
|
785
1041
|
ConstDependency,
|
|
786
1042
|
new ConstDependency.Template()
|
|
@@ -812,10 +1068,9 @@ class HtmlModulesPlugin {
|
|
|
812
1068
|
HtmlEntryDependency,
|
|
813
1069
|
new HtmlEntryDependency.Template()
|
|
814
1070
|
);
|
|
815
|
-
// Inline `<script>` content
|
|
816
|
-
//
|
|
817
|
-
//
|
|
818
|
-
// template rewrites the original tag to `<script src=…>`.
|
|
1071
|
+
// Inline `<script>` content becomes its own entry through a
|
|
1072
|
+
// `data:text/javascript,...` request, the same pipeline as
|
|
1073
|
+
// `<script src>`; the template then rewrites the tag.
|
|
819
1074
|
compilation.dependencyFactories.set(
|
|
820
1075
|
HtmlInlineScriptDependency,
|
|
821
1076
|
normalModuleFactory
|
|
@@ -824,11 +1079,9 @@ class HtmlModulesPlugin {
|
|
|
824
1079
|
HtmlInlineScriptDependency,
|
|
825
1080
|
new HtmlInlineScriptDependency.Template()
|
|
826
1081
|
);
|
|
827
|
-
// Inline `<style>` content
|
|
828
|
-
//
|
|
829
|
-
//
|
|
830
|
-
// generation data (`css-text` channel set by CssGenerator
|
|
831
|
-
// when `exportType` is `"text"`).
|
|
1082
|
+
// Inline `<style>` content goes through the CSS pipeline as a
|
|
1083
|
+
// `data:text/css` module; the template reads the processed text
|
|
1084
|
+
// from the `css-text` code-generation channel.
|
|
832
1085
|
compilation.dependencyFactories.set(
|
|
833
1086
|
HtmlInlineStyleDependency,
|
|
834
1087
|
normalModuleFactory
|
|
@@ -888,7 +1141,8 @@ class HtmlModulesPlugin {
|
|
|
888
1141
|
);
|
|
889
1142
|
return new (getHtmlGenerator())(
|
|
890
1143
|
generatorOptions,
|
|
891
|
-
compilation.moduleGraph
|
|
1144
|
+
compilation.moduleGraph,
|
|
1145
|
+
(module) => getPageOnlyEntry(compilation, module) !== undefined
|
|
892
1146
|
);
|
|
893
1147
|
});
|
|
894
1148
|
|
|
@@ -896,61 +1150,45 @@ class HtmlModulesPlugin {
|
|
|
896
1150
|
PLUGIN_NAME,
|
|
897
1151
|
(result, module) => {
|
|
898
1152
|
if (module.type === HTML_MODULE_TYPE) {
|
|
899
|
-
const [source, ...rest] = result;
|
|
900
|
-
//
|
|
901
|
-
//
|
|
902
|
-
//
|
|
903
|
-
// and the generator's render base in sync.
|
|
1153
|
+
const [source, ...rest] = removeBOMFromResult(result);
|
|
1154
|
+
// Run here, where the returned source becomes the module's stored
|
|
1155
|
+
// source, so the parser's dependency offsets and the generator's
|
|
1156
|
+
// render base stay in sync.
|
|
904
1157
|
const parser = /** @type {HtmlParser} */ (module.parser);
|
|
905
1158
|
|
|
906
|
-
return [parser.applyTemplate(
|
|
1159
|
+
return [parser.applyTemplate(source, module), ...rest];
|
|
907
1160
|
}
|
|
908
1161
|
|
|
909
1162
|
return result;
|
|
910
1163
|
}
|
|
911
1164
|
);
|
|
912
1165
|
|
|
913
|
-
//
|
|
914
|
-
//
|
|
915
|
-
// `
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
//
|
|
919
|
-
//
|
|
920
|
-
//
|
|
921
|
-
//
|
|
922
|
-
//
|
|
923
|
-
|
|
924
|
-
// `
|
|
925
|
-
//
|
|
926
|
-
//
|
|
927
|
-
// intentionally omitted so `[name]` resolves to the HTML
|
|
928
|
-
// source's basename (e.g. `page` for `./page.html`) rather
|
|
929
|
-
// than the importing chunk's name (e.g. `main`). A per-module
|
|
930
|
-
// content hash is computed from the rewritten HTML so the
|
|
931
|
-
// template's `[contenthash]` placeholder works; the
|
|
932
|
-
// compilation hash is also forwarded so `[fullhash]` /
|
|
933
|
-
// `[hash]` work in user-supplied templates.
|
|
934
|
-
|
|
935
|
-
// Sentinel-resolved content and its content hash depend only on
|
|
936
|
-
// the HTML-type module source — not on the chunk or output
|
|
937
|
-
// filename — yet `renderManifest` runs per `(chunk, module)`.
|
|
938
|
-
// Memoize so a module landing in multiple chunks resolves and
|
|
939
|
-
// hashes its sentinels once. Scoped to this compilation because
|
|
940
|
-
// sentinel resolution embeds chunk filenames, which change
|
|
941
|
-
// across rebuilds; weakly keyed by source so entries release.
|
|
1166
|
+
// WHY: emit extracted `.html` files for any HTML module that opted in.
|
|
1167
|
+
// `HtmlGenerator#_shouldExtract` computes that opt-in —
|
|
1168
|
+
// `module.generator.html.extract: true` always extracts, `false` never,
|
|
1169
|
+
// and unset extracts only a compilation entry — and the iteration below
|
|
1170
|
+
// picks up only modules whose generator reported the `html` source type,
|
|
1171
|
+
// so that decision is honoured implicitly. The filename comes from
|
|
1172
|
+
// `output.htmlFilename` for initial chunks and `output.htmlChunkFilename`
|
|
1173
|
+
// otherwise, mirroring the CSS pipeline, and the path data follows the
|
|
1174
|
+
// asset-module pattern with `chunk` deliberately left out, so `[name]`
|
|
1175
|
+
// resolves to the HTML source's basename rather than the chunk's.
|
|
1176
|
+
|
|
1177
|
+
// `renderManifest` runs per `(chunk, module)`, but resolved content and
|
|
1178
|
+
// its hash depend only on the module source, so memoize. Scoped to this
|
|
1179
|
+
// compilation, since resolution embeds chunk filenames.
|
|
942
1180
|
/** @type {WeakMap<import("webpack-sources").Source, { resolvedContent: string, contentHash: string }>} */
|
|
943
1181
|
const resolvedSentinelHashCache = new WeakMap();
|
|
944
1182
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
) => {
|
|
1183
|
+
/**
|
|
1184
|
+
* Computes an HTML page's emitted filename, chunk-URL-resolved content and
|
|
1185
|
+
* content hash. Links to other pages stay sentinels, so a page's filename
|
|
1186
|
+
* never depends on the filenames of the pages it links to.
|
|
1187
|
+
* @param {NormalModule} module the page's html module
|
|
1188
|
+
* @param {import("../Chunk")} chunk chunk the page is emitted from
|
|
1189
|
+
* @returns {{ resolvedContent: string, contentHash: string, filename: string, info: import("../Compilation").AssetInfo } | undefined} the page's emit, or `undefined` when it generates no html
|
|
1190
|
+
*/
|
|
1191
|
+
const computePageEmit = (module, chunk) => {
|
|
954
1192
|
const { chunkGraph, outputOptions } = compilation;
|
|
955
1193
|
const codeGenResult =
|
|
956
1194
|
/** @type {import("../CodeGenerationResults")} */ (
|
|
@@ -960,15 +1198,12 @@ class HtmlModulesPlugin {
|
|
|
960
1198
|
if (!placeholderSource) return undefined;
|
|
961
1199
|
let cached = resolvedSentinelHashCache.get(placeholderSource);
|
|
962
1200
|
if (cached === undefined) {
|
|
963
|
-
// Resolve chunk-URL sentinels
|
|
964
|
-
// `[contenthash]`
|
|
965
|
-
//
|
|
966
|
-
|
|
967
|
-
//
|
|
968
|
-
//
|
|
969
|
-
// Asset URL sentinels (from `HtmlEntryDependency` resource-hint
|
|
970
|
-
// tags) resolve here too — deferred from template.apply so it
|
|
971
|
-
// doesn't race with asset-module codegen.
|
|
1201
|
+
// Resolve chunk-URL sentinels before hashing, so the page's
|
|
1202
|
+
// `[contenthash]` tracks the referenced chunks. An inlined chunk has
|
|
1203
|
+
// no URL, so its sentinel carries the chunk content hash instead.
|
|
1204
|
+
|
|
1205
|
+
// Asset URL sentinels resolve here rather than in `template.apply`,
|
|
1206
|
+
// which would race with asset-module codegen.
|
|
972
1207
|
const resolvedContent = getHtmlGenerator().resolveAssetUrlSentinels(
|
|
973
1208
|
getHtmlGenerator().embedInlineChunkHashes(
|
|
974
1209
|
getHtmlGenerator().resolveChunkUrlSentinels(
|
|
@@ -1027,14 +1262,15 @@ class HtmlModulesPlugin {
|
|
|
1027
1262
|
};
|
|
1028
1263
|
};
|
|
1029
1264
|
|
|
1030
|
-
// Emitted filename of a linked `type: "html"` page, keyed by its entry
|
|
1031
|
-
// name. Looked up from the page's own entry chunk so it's independent of
|
|
1032
|
-
// chunk render order; cached for the compilation.
|
|
1033
1265
|
/** @type {Map<string, string>} */
|
|
1034
1266
|
const htmlPageFilenameCache = new Map();
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1267
|
+
/**
|
|
1268
|
+
* Emitted filename of a linked `type: "html"` page, read from the page's
|
|
1269
|
+
* own entry chunk so chunk render order cannot affect it.
|
|
1270
|
+
* @param {string} entryName entry name of the linked page
|
|
1271
|
+
* @returns {string} the page's emitted filename, `"data:,"` when it has none
|
|
1272
|
+
*/
|
|
1273
|
+
const computePageFilenameByEntry = (entryName) => {
|
|
1038
1274
|
const cached = htmlPageFilenameCache.get(entryName);
|
|
1039
1275
|
if (cached !== undefined) return cached;
|
|
1040
1276
|
let filename = "data:,";
|
|
@@ -1063,9 +1299,8 @@ class HtmlModulesPlugin {
|
|
|
1063
1299
|
compilation.hooks.renderManifest.tap(
|
|
1064
1300
|
PLUGIN_NAME,
|
|
1065
1301
|
(result, { chunk }) => {
|
|
1066
|
-
// HMR's `HotUpdateChunk`s
|
|
1067
|
-
//
|
|
1068
|
-
// for them would create stray hot-update HTML files.
|
|
1302
|
+
// HMR's `HotUpdateChunk`s reach this hook but are not output chunks,
|
|
1303
|
+
// so extracting `.html` for them would emit stray hot-update files.
|
|
1069
1304
|
// `CssModulesPlugin` early-returns for the same reason.
|
|
1070
1305
|
if (chunk instanceof HotUpdateChunk) return result;
|
|
1071
1306
|
const { chunkGraph } = compilation;
|
|
@@ -1079,12 +1314,13 @@ class HtmlModulesPlugin {
|
|
|
1079
1314
|
const outputOptions = compilation.outputOptions;
|
|
1080
1315
|
for (const module of modules) {
|
|
1081
1316
|
const normalModule = /** @type {NormalModule} */ (module);
|
|
1082
|
-
// `<iframe srcdoc>`
|
|
1083
|
-
// can write the processed markup back
|
|
1084
|
-
//
|
|
1085
|
-
//
|
|
1086
|
-
//
|
|
1087
|
-
//
|
|
1317
|
+
// WHY: an `<iframe srcdoc>` module exposes `html` only so that
|
|
1318
|
+
// `HtmlInlineHtmlDependency` can write the processed markup back
|
|
1319
|
+
// into the host attribute; it is never a standalone page.
|
|
1320
|
+
// `generator.extract: "inline"` marks it so no `.html` file is
|
|
1321
|
+
// emitted — without it they would collide on the `data:text/html`
|
|
1322
|
+
// to chunk-name path, every srcdoc module in a chunk emitting
|
|
1323
|
+
// `<chunk>.html`. An O(1) flag check rather than a scan.
|
|
1088
1324
|
const generatorOptions = normalModule.generatorOptions;
|
|
1089
1325
|
if (generatorOptions && generatorOptions.extract === "inline") {
|
|
1090
1326
|
continue;
|
|
@@ -1094,11 +1330,9 @@ class HtmlModulesPlugin {
|
|
|
1094
1330
|
if (!emit) continue;
|
|
1095
1331
|
const { resolvedContent, contentHash, filename, info } = emit;
|
|
1096
1332
|
|
|
1097
|
-
// Resolve
|
|
1098
|
-
//
|
|
1099
|
-
//
|
|
1100
|
-
// a subdirectory. A relative `<base href>` prepends `../`s so the
|
|
1101
|
-
// base can't misdirect the rewritten URLs (see `HtmlParser`).
|
|
1333
|
+
// Resolve the remaining `[webpack/auto]` placeholders against the
|
|
1334
|
+
// emitted page's own location, so URLs stay relative to `output.path`
|
|
1335
|
+
// from a subdirectory. A relative `<base href>` prepends `../`s.
|
|
1102
1336
|
const basePrefix =
|
|
1103
1337
|
/** @type {HtmlModuleBuildInfo} */ (normalModule.buildInfo)
|
|
1104
1338
|
.baseUrlPrefix || "";
|
|
@@ -1120,12 +1354,9 @@ class HtmlModulesPlugin {
|
|
|
1120
1354
|
.split(autoPlaceholder)
|
|
1121
1355
|
.join(undoPath);
|
|
1122
1356
|
const finalSource = new RawSource(finalContent);
|
|
1123
|
-
//
|
|
1124
|
-
//
|
|
1125
|
-
//
|
|
1126
|
-
// the asset cache key and the post-undo-path content in the hash so the
|
|
1127
|
-
// asset cache can't reuse one variant's bytes at another variant's URL.
|
|
1128
|
-
// Unchanged content reuses the memoized hash instead of re-digesting.
|
|
1357
|
+
// One module can land in several chunks whose filename shapes give
|
|
1358
|
+
// different undo paths, so the emitted filename joins the cache key
|
|
1359
|
+
// and the post-undo content the hash — else variants alias.
|
|
1129
1360
|
const finalContentHash =
|
|
1130
1361
|
finalContent === resolvedContent
|
|
1131
1362
|
? contentHash
|
|
@@ -1165,6 +1396,16 @@ class HtmlModulesPlugin {
|
|
|
1165
1396
|
jsHooks.render.tap(PLUGIN_NAME, (source, renderContext) => {
|
|
1166
1397
|
// No HTML modules ⇒ no sentinels; skip materializing the JS source.
|
|
1167
1398
|
if (htmlModules.size === 0) return source;
|
|
1399
|
+
// Chunks without HTML modules can't carry HTML sentinels — avoid
|
|
1400
|
+
// ConcatSource.source() on the common pure-JS chunk path.
|
|
1401
|
+
if (
|
|
1402
|
+
!HtmlModulesPlugin.chunkHasHtml(
|
|
1403
|
+
renderContext.chunk,
|
|
1404
|
+
compilation.chunkGraph
|
|
1405
|
+
)
|
|
1406
|
+
) {
|
|
1407
|
+
return source;
|
|
1408
|
+
}
|
|
1168
1409
|
const raw = source.source();
|
|
1169
1410
|
if (typeof raw !== "string") return source;
|
|
1170
1411
|
// Every sentinel shares this prefix — one scan answers the common
|
|
@@ -1235,6 +1476,29 @@ class HtmlModulesPlugin {
|
|
|
1235
1476
|
}
|
|
1236
1477
|
);
|
|
1237
1478
|
}
|
|
1479
|
+
|
|
1480
|
+
/**
|
|
1481
|
+
* Returns true, when the chunk has html.
|
|
1482
|
+
* @param {Chunk} chunk chunk
|
|
1483
|
+
* @param {ChunkGraph} chunkGraph chunk graph
|
|
1484
|
+
* @returns {boolean} true, when the chunk has html
|
|
1485
|
+
*/
|
|
1486
|
+
static chunkHasHtml(chunk, chunkGraph) {
|
|
1487
|
+
if (chunkGraph.getChunkModulesIterableBySourceType(chunk, HTML_TYPE)) {
|
|
1488
|
+
return true;
|
|
1489
|
+
}
|
|
1490
|
+
// Scope-hoisted HTML loses HTML_TYPE on the ConcatenatedModule, but its
|
|
1491
|
+
// JS export can still carry unresolved sentinels that need this path.
|
|
1492
|
+
for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
|
|
1493
|
+
if (module instanceof HtmlModule) return true;
|
|
1494
|
+
if (module instanceof ConcatenatedModule) {
|
|
1495
|
+
for (const inner of module.modules) {
|
|
1496
|
+
if (inner instanceof HtmlModule) return true;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return false;
|
|
1501
|
+
}
|
|
1238
1502
|
}
|
|
1239
1503
|
|
|
1240
1504
|
/**
|