webpack 5.108.4 → 5.109.1
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/bin/webpack.js +12 -0
- package/lib/APIPlugin.js +48 -29
- package/lib/CacheFacade.js +8 -0
- package/lib/ChunkGraph.js +17 -15
- package/lib/ChunkGroup.js +1 -0
- package/lib/CompatibilityPlugin.js +62 -29
- package/lib/Compilation.js +58 -6
- package/lib/ConstPlugin.js +11 -11
- package/lib/ContextModule.js +239 -6
- package/lib/ContextModuleFactory.js +139 -14
- package/lib/DefinePlugin.js +433 -112
- package/lib/Entrypoint.js +1 -1
- package/lib/ExportsInfo.js +22 -5
- package/lib/ExportsInfoApiPlugin.js +2 -2
- package/lib/ExternalModule.js +107 -5
- package/lib/ExternalModuleFactoryPlugin.js +20 -1
- package/lib/FileSystemInfo.js +256 -100
- package/lib/FlagDependencyUsagePlugin.js +33 -12
- package/lib/HotModuleReplacementPlugin.js +18 -15
- package/lib/InitFragment.js +20 -32
- package/lib/Module.js +3 -0
- package/lib/ModuleFilenameHelpers.js +2 -2
- package/lib/ModuleTypeConstants.js +8 -1
- package/lib/MultiCompiler.js +13 -2
- package/lib/MultiWatching.js +1 -0
- package/lib/NodeStuffPlugin.js +51 -33
- package/lib/NormalModule.js +175 -401
- package/lib/NormalModuleFactory.js +76 -2
- package/lib/ProgressPlugin.js +211 -119
- package/lib/ProvidePlugin.js +2 -2
- package/lib/RuntimeGlobals.js +47 -0
- package/lib/RuntimePlugin.js +67 -107
- package/lib/RuntimeTemplate.js +304 -16
- package/lib/Template.js +23 -3
- package/lib/UseStrictPlugin.js +1 -1
- package/lib/WebpackIsIncludedPlugin.js +1 -1
- package/lib/WebpackOptionsApply.js +24 -19
- package/lib/asset/AssetGenerator.js +110 -28
- package/lib/asset/AssetModulesPlugin.js +92 -2
- package/lib/asset/WebManifestGenerator.js +164 -0
- package/lib/asset/WebManifestParser.js +130 -0
- package/lib/async-modules/AwaitDependenciesInitFragment.js +14 -4
- package/lib/async-modules/isGeneratorLowered.js +26 -0
- package/lib/cache/PackFileCacheStrategy.js +9 -3
- package/lib/config/browserslistTargetHandler.js +40 -0
- package/lib/config/defaults.js +219 -29
- package/lib/config/normalization.js +26 -0
- package/lib/config/target.js +9 -1
- package/lib/container/HoistContainerReferencesPlugin.js +47 -55
- package/lib/css/CssGenerator.js +40 -31
- package/lib/css/CssLoadingRuntimeModule.js +5 -1
- package/lib/css/CssModulesPlugin.js +13 -0
- package/lib/css/CssParser.js +729 -313
- package/lib/css/syntax.js +1371 -861
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -6
- package/lib/dependencies/AMDPlugin.js +2 -2
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +13 -13
- package/lib/dependencies/CommonJsDependencyHelpers.js +39 -0
- package/lib/dependencies/CommonJsExportRequireDependency.js +19 -0
- package/lib/dependencies/CommonJsExportsDependency.js +47 -2
- package/lib/dependencies/CommonJsExportsParserPlugin.js +10 -10
- package/lib/dependencies/CommonJsImportsParserPlugin.js +18 -18
- package/lib/dependencies/CommonJsPlugin.js +2 -2
- package/lib/dependencies/CommonJsRequireDependency.js +26 -1
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +32 -1
- package/lib/dependencies/ContextDependencyHelpers.js +3 -3
- package/lib/dependencies/CreateRequireParserPlugin.js +6 -6
- package/lib/dependencies/CssIcssExportDependency.js +162 -71
- package/lib/dependencies/CssUrlDependency.js +35 -4
- package/lib/dependencies/ExternalModuleInitFragmentDependency.js +2 -2
- package/lib/dependencies/HarmonyCompatibilityDependency.js +32 -14
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +43 -13
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +2 -1
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +7 -19
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +17 -9
- package/lib/dependencies/HarmonyImportDependency.js +13 -2
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +11 -11
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +10 -7
- package/lib/dependencies/HarmonyModulesPlugin.js +6 -0
- package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -1
- package/lib/dependencies/HtmlEntryDependency.js +797 -172
- package/lib/dependencies/HtmlSourceDependency.js +26 -0
- package/lib/dependencies/ImportDependency.js +43 -1
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +31 -18
- package/lib/dependencies/ImportMetaContextPlugin.js +38 -7
- package/lib/dependencies/ImportMetaGlobDependency.js +81 -0
- package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +78 -0
- package/lib/dependencies/ImportMetaGlobHelpers.js +660 -0
- package/lib/dependencies/ImportMetaPlugin.js +532 -180
- package/lib/dependencies/ImportMetaResolveDependency.js +90 -0
- package/lib/dependencies/ImportParserPlugin.js +80 -17
- package/lib/dependencies/ImportPhase.js +10 -8
- package/lib/dependencies/LoaderPlugin.js +5 -1
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +3 -6
- package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +4 -11
- package/lib/dependencies/SystemPlugin.js +2 -4
- package/lib/dependencies/TopLevelAwaitDependency.js +93 -0
- package/lib/dependencies/URLDependency.js +141 -21
- package/lib/dependencies/{WorkerPlugin.js → WorkerAndWorkletPlugin.js} +324 -112
- package/lib/dependencies/WorkerDependency.js +86 -18
- package/lib/dependencies/WorkletDependency.js +278 -0
- package/lib/dll/DelegatedModuleFactoryPlugin.js +19 -0
- package/lib/errors/EnvironmentNotSupportAsyncWarning.js +1 -1
- package/lib/errors/LoaderLoadingError.js +20 -0
- package/lib/errors/ModuleParseError.js +39 -22
- package/lib/errors/NodeStuffInWebError.js +1 -1
- package/lib/esm/ModuleChunkFormatPlugin.js +47 -14
- package/lib/esm/ModuleChunkLoadingPlugin.js +8 -1
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +29 -1
- package/lib/hmr/lazyCompilationBackend.js +51 -12
- package/lib/html/HtmlGenerator.js +907 -15
- package/lib/html/HtmlModule.js +2 -2
- package/lib/html/HtmlModulesPlugin.js +610 -166
- package/lib/html/HtmlParser.js +603 -247
- package/lib/html/favicon.svg +1 -0
- package/lib/html/syntax.js +3451 -2762
- package/lib/ids/IdHelpers.js +25 -11
- package/lib/index.js +6 -0
- package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +4 -5
- package/lib/javascript/BasicEvaluatedExpression.js +366 -48
- package/lib/javascript/JavascriptGenerator.js +197 -49
- package/lib/javascript/JavascriptModulesPlugin.js +178 -24
- package/lib/javascript/JavascriptParser.js +704 -355
- package/lib/javascript/JavascriptParserHelpers.js +3 -6
- package/lib/javascript/syntax.js +5037 -0
- package/lib/library/ModuleLibraryPlugin.js +38 -1
- package/lib/loaders/LoaderRunner.js +714 -0
- package/lib/loaders/loadLoader.js +100 -0
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +29 -2
- package/lib/node/ReadFileCompileWasmPlugin.js +24 -2
- package/lib/optimize/AggressiveMergingPlugin.js +19 -15
- package/lib/optimize/ConcatenatedModule.js +139 -31
- package/lib/optimize/FlagIncludedChunksPlugin.js +13 -3
- package/lib/optimize/InnerGraphPlugin.js +50 -30
- package/lib/optimize/ModuleConcatenationPlugin.js +139 -24
- package/lib/optimize/SideEffectsFlagPlugin.js +86 -43
- package/lib/optimize/SplitChunksPlugin.js +146 -44
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +15 -0
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +24 -13
- package/lib/prefetch/ResourceHintPlugin.js +687 -0
- package/lib/prefetch/ResourceHintRuntimeModule.js +149 -0
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +210 -0
- package/lib/prefetch/parseResourceHintOptions.js +103 -0
- package/lib/rules/RuleSetCompiler.js +114 -0
- package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +56 -0
- package/lib/runtime/AsyncModuleRuntimeModule.js +24 -8
- package/lib/runtime/AutoPublicPathRuntimeModule.js +7 -1
- package/lib/runtime/CommonJsWrapRuntimeModule.js +37 -0
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +59 -0
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +204 -8
- package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +4 -1
- package/lib/schemes/HttpUriPlugin.js +40 -1
- package/lib/schemes/VirtualUrlPlugin.js +1 -2
- package/lib/serialization/BinaryMiddleware.js +270 -938
- package/lib/serialization/FileMiddleware.js +29 -3
- package/lib/stats/DefaultStatsFactoryPlugin.js +229 -194
- package/lib/stats/DefaultStatsPresetPlugin.js +2 -0
- package/lib/stats/DefaultStatsPrinterPlugin.js +36 -168
- package/lib/stats/StatsFactory.js +46 -17
- package/lib/url/URLParserPlugin.js +66 -13
- package/lib/util/AsyncQueue.js +122 -72
- package/lib/util/SetHelpers.js +1 -1
- package/lib/util/StackedMap.js +122 -48
- package/lib/util/binarySearchBounds.js +2 -2
- package/lib/util/concatenate.js +40 -14
- package/lib/util/createHooksRegistry.js +13 -5
- package/lib/util/dataURL.js +2 -2
- package/lib/util/deterministicGrouping.js +7 -5
- package/lib/util/formatSize.js +6 -2
- package/lib/util/globUtils.js +710 -0
- package/lib/util/identifier.js +23 -6
- package/lib/util/implicitTypeLoaderFallback.js +62 -0
- package/lib/util/internalSerializables.js +88 -71
- package/lib/util/magicComment.js +121 -25
- package/lib/util/numberHash.js +2 -2
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +24 -18
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +33 -22
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +79 -16
- package/lib/web/FetchCompileAsyncWasmPlugin.js +19 -0
- package/lib/web/FetchCompileWasmPlugin.js +14 -0
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +2 -0
- package/lib/webpack.js +65 -0
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +3 -0
- package/module.d.ts +21 -0
- package/package.json +12 -11
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +759 -36
- package/schemas/plugins/HtmlParserOptions.check.js +1 -1
- package/schemas/plugins/ProgressPlugin.check.js +1 -1
- package/schemas/plugins/ProgressPlugin.json +17 -1
- package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
- package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
- package/schemas/plugins/container/ExternalsType.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssParserOptions.check.js +1 -1
- package/types.d.ts +1212 -99
|
@@ -23,7 +23,10 @@ const {
|
|
|
23
23
|
JAVASCRIPT_TYPES,
|
|
24
24
|
NO_TYPES
|
|
25
25
|
} = require("../ModuleSourceTypeConstants");
|
|
26
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
ASSET_MODULE_TYPE,
|
|
28
|
+
ASSET_MODULE_TYPE_WEBMANIFEST
|
|
29
|
+
} = require("../ModuleTypeConstants");
|
|
27
30
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
|
28
31
|
const createHash = require("../util/createHash");
|
|
29
32
|
const { makePathsRelative } = require("../util/identifier");
|
|
@@ -45,6 +48,7 @@ const getMimeTypes = memoize(() => require("../util/mimeTypes"));
|
|
|
45
48
|
/** @typedef {import("../../declarations/WebpackOptions").AssetResourceGeneratorOptions} AssetResourceGeneratorOptions */
|
|
46
49
|
/** @typedef {import("../../declarations/WebpackOptions").RawPublicPath} RawPublicPath */
|
|
47
50
|
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
|
51
|
+
/** @typedef {import("../Compilation")} Compilation */
|
|
48
52
|
/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
|
|
49
53
|
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
|
50
54
|
/** @typedef {import("../Generator").UpdateHashContext} UpdateHashContext */
|
|
@@ -56,12 +60,28 @@ const getMimeTypes = memoize(() => require("../util/mimeTypes"));
|
|
|
56
60
|
/** @typedef {import("../Module").SourceTypes} SourceTypes */
|
|
57
61
|
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
|
58
62
|
/** @typedef {import("../NormalModule")} NormalModule */
|
|
63
|
+
/** @typedef {import("../dependencies/URLDependency")} URLDependency */
|
|
59
64
|
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
|
60
65
|
/** @typedef {import("../util/Hash")} Hash */
|
|
61
66
|
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
|
|
62
67
|
|
|
63
68
|
/** @typedef {(source: string | Buffer, context: { filename: string, module: Module }) => string} DataUrlFunction */
|
|
64
69
|
|
|
70
|
+
// slash separating a module type from its subtype (`css/auto` -> `css`)
|
|
71
|
+
const TYPE_SEPARATOR_CHAR_CODE = 47;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether a module type's prefix (the part before `/`) equals `prefix`, without
|
|
75
|
+
* allocating the substring `type.split("/")[0]` would produce.
|
|
76
|
+
* @param {string} type module type (e.g. `javascript/auto`)
|
|
77
|
+
* @param {string} prefix expected prefix (e.g. `javascript`)
|
|
78
|
+
* @returns {boolean} whether the type's prefix equals `prefix`
|
|
79
|
+
*/
|
|
80
|
+
const typePrefixEquals = (type, prefix) =>
|
|
81
|
+
type.startsWith(prefix) &&
|
|
82
|
+
(type.length === prefix.length ||
|
|
83
|
+
type.charCodeAt(prefix.length) === TYPE_SEPARATOR_CHAR_CODE);
|
|
84
|
+
|
|
65
85
|
/**
|
|
66
86
|
* Merges maybe arrays.
|
|
67
87
|
* @template T
|
|
@@ -156,14 +176,10 @@ const encodeDataUri = (encoding, source) => {
|
|
|
156
176
|
case false: {
|
|
157
177
|
const content = source.source();
|
|
158
178
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
179
|
+
encodedContent =
|
|
180
|
+
typeof content === "string" ? content : content.toString("utf8");
|
|
162
181
|
|
|
163
|
-
encodedContent = encodeURIComponent(
|
|
164
|
-
/** @type {string} */
|
|
165
|
-
(encodedContent)
|
|
166
|
-
).replace(
|
|
182
|
+
encodedContent = encodeURIComponent(encodedContent).replace(
|
|
167
183
|
/[!'()*]/g,
|
|
168
184
|
(character) =>
|
|
169
185
|
`%${/** @type {number} */ (character.codePointAt(0)).toString(16)}`
|
|
@@ -192,9 +208,9 @@ const decodeDataUriContent = (encoding, content) => {
|
|
|
192
208
|
|
|
193
209
|
// If we can't decode return the original body
|
|
194
210
|
try {
|
|
195
|
-
return Buffer.from(decodeURIComponent(content), "
|
|
211
|
+
return Buffer.from(decodeURIComponent(content), "utf8");
|
|
196
212
|
} catch (_) {
|
|
197
|
-
return Buffer.from(content, "
|
|
213
|
+
return Buffer.from(content, "utf8");
|
|
198
214
|
}
|
|
199
215
|
};
|
|
200
216
|
|
|
@@ -209,6 +225,7 @@ class AssetGenerator extends Generator {
|
|
|
209
225
|
* @param {RawPublicPath=} publicPath override for output.assetModulePublicPath
|
|
210
226
|
* @param {AssetModuleOutputPath=} outputPath the output path for the emitted file which is not included in the runtime import
|
|
211
227
|
* @param {boolean=} emit generate output asset
|
|
228
|
+
* @param {Compilation=} compilation the compilation (`getTypes` has no generate context, so the analyzable-output decision reads `output.module`/`output.publicPath` from here)
|
|
212
229
|
*/
|
|
213
230
|
constructor(
|
|
214
231
|
moduleGraph,
|
|
@@ -216,7 +233,8 @@ class AssetGenerator extends Generator {
|
|
|
216
233
|
filename,
|
|
217
234
|
publicPath,
|
|
218
235
|
outputPath,
|
|
219
|
-
emit
|
|
236
|
+
emit,
|
|
237
|
+
compilation
|
|
220
238
|
) {
|
|
221
239
|
super();
|
|
222
240
|
/** @type {AssetGeneratorOptions["dataUrl"] | undefined} */
|
|
@@ -229,6 +247,8 @@ class AssetGenerator extends Generator {
|
|
|
229
247
|
this.outputPath = outputPath;
|
|
230
248
|
/** @type {boolean | undefined} */
|
|
231
249
|
this.emit = emit;
|
|
250
|
+
/** @type {Compilation | undefined} */
|
|
251
|
+
this._compilation = compilation;
|
|
232
252
|
/** @type {ModuleGraph} */
|
|
233
253
|
this._moduleGraph = moduleGraph;
|
|
234
254
|
}
|
|
@@ -697,36 +717,101 @@ class AssetGenerator extends Generator {
|
|
|
697
717
|
}
|
|
698
718
|
}
|
|
699
719
|
|
|
720
|
+
/**
|
|
721
|
+
* Returns whether the effective publicPath yields a chunk-independent absolute
|
|
722
|
+
* url (scheme-relative, protocol-absolute, or root-absolute) with no hash tokens.
|
|
723
|
+
* Only then is a `new URL` literal correct for every chunk the asset is shared by,
|
|
724
|
+
* so the `module.exports` wrapper can be dropped in favor of the `asset-url` type.
|
|
725
|
+
* @returns {boolean} true when the publicPath is a token-free absolute string
|
|
726
|
+
*/
|
|
727
|
+
_hasAbsolutePublicPath() {
|
|
728
|
+
const publicPath =
|
|
729
|
+
this.publicPath !== undefined
|
|
730
|
+
? this.publicPath
|
|
731
|
+
: this._compilation && this._compilation.outputOptions.publicPath;
|
|
732
|
+
return (
|
|
733
|
+
typeof publicPath === "string" &&
|
|
734
|
+
!publicPath.includes("[") &&
|
|
735
|
+
(publicPath.startsWith("/") ||
|
|
736
|
+
/^[a-z][a-z\d+\-.]*:\/\//i.test(publicPath))
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
|
|
700
740
|
/**
|
|
701
741
|
* Returns the source types available for this module.
|
|
702
742
|
* @param {NormalModule} module fresh module
|
|
703
743
|
* @returns {SourceTypes} available types (do not mutate)
|
|
704
744
|
*/
|
|
705
745
|
getTypes(module) {
|
|
706
|
-
/** @type {Set<string>} */
|
|
707
|
-
const sourceTypes = new Set();
|
|
708
746
|
const connections = this._moduleGraph.getIncomingConnections(module);
|
|
709
747
|
|
|
748
|
+
// Only ESM output can drop a bare `new URL()` to an analyzable asset-url; without
|
|
749
|
+
// it every JS consumer needs the wrapper, so skip the per-connection dependency
|
|
750
|
+
// probe entirely and keep the pre-existing cheap path.
|
|
751
|
+
const isModule = Boolean(
|
|
752
|
+
this._compilation && this._compilation.outputOptions.module
|
|
753
|
+
);
|
|
754
|
+
|
|
755
|
+
// Collapse the incoming origin types into flags instead of a Set of prefixes:
|
|
756
|
+
// on assets shared by many modules this loop runs millions of times, so avoid
|
|
757
|
+
// the per-connection `split("/")` allocation and stop early when the result is fixed.
|
|
758
|
+
let hasOrigin = false;
|
|
759
|
+
// JS origin that needs the `module.exports = …` wrapper (not a `new URL` ref).
|
|
760
|
+
let hasOtherJs = false;
|
|
761
|
+
// JS origin via `new URL(…, import.meta.url)` — droppable to `asset-url` in ESM.
|
|
762
|
+
let hasUrlJs = false;
|
|
763
|
+
// A manifest embeds a bare URL string (like css/html), so its icons must
|
|
764
|
+
// resolve to `ASSET_URL_TYPE` rather than the JS runtime form.
|
|
765
|
+
let hasUrl = false;
|
|
710
766
|
for (const connection of connections) {
|
|
711
|
-
|
|
767
|
+
const originModule = connection.originModule;
|
|
768
|
+
if (!originModule) {
|
|
712
769
|
continue;
|
|
713
770
|
}
|
|
714
|
-
|
|
715
|
-
|
|
771
|
+
hasOrigin = true;
|
|
772
|
+
const originType = originModule.type;
|
|
773
|
+
if (originType === ASSET_MODULE_TYPE_WEBMANIFEST) {
|
|
774
|
+
hasUrl = true;
|
|
775
|
+
} else if (typePrefixEquals(originType, JAVASCRIPT_TYPE)) {
|
|
776
|
+
// Only a bare `new URL()` becomes the analyzable literal; relative and
|
|
777
|
+
// prefetch/preload refs keep the runtime form and still need the wrapper.
|
|
778
|
+
const dependency = isModule && connection.dependency;
|
|
779
|
+
if (
|
|
780
|
+
dependency &&
|
|
781
|
+
dependency.type === "new URL()" &&
|
|
782
|
+
!(/** @type {URLDependency} */ (dependency).relative) &&
|
|
783
|
+
!(/** @type {URLDependency} */ (dependency).prefetch) &&
|
|
784
|
+
!(/** @type {URLDependency} */ (dependency).preload)
|
|
785
|
+
) {
|
|
786
|
+
hasUrlJs = true;
|
|
787
|
+
} else {
|
|
788
|
+
hasOtherJs = true;
|
|
789
|
+
}
|
|
790
|
+
} else if (
|
|
791
|
+
typePrefixEquals(originType, CSS_TYPE) ||
|
|
792
|
+
typePrefixEquals(originType, HTML_TYPE)
|
|
793
|
+
) {
|
|
794
|
+
hasUrl = true;
|
|
795
|
+
}
|
|
796
|
+
// Once a non-URL JS consumer and a url consumer coexist the result is fixed.
|
|
797
|
+
if (hasOtherJs && hasUrl) break;
|
|
716
798
|
}
|
|
717
799
|
|
|
800
|
+
const jsAsAssetUrl =
|
|
801
|
+
isModule && hasUrlJs && !hasOtherJs && this._hasAbsolutePublicPath();
|
|
802
|
+
// JS wrapper is needed for non-URL JS consumers, or URL consumers not dropped to asset-url.
|
|
803
|
+
const wantJs = hasOtherJs || (hasUrlJs && !jsAsAssetUrl);
|
|
804
|
+
const wantUrl = hasUrl || jsAsAssetUrl;
|
|
805
|
+
|
|
718
806
|
if (
|
|
719
807
|
(module.buildInfo &&
|
|
720
808
|
/** @type {AssetModuleBuildInfo} */ (module.buildInfo).dataUrl) ||
|
|
721
809
|
this.emit === false
|
|
722
810
|
) {
|
|
723
|
-
if (
|
|
724
|
-
if (
|
|
725
|
-
sourceTypes.has(JAVASCRIPT_TYPE) &&
|
|
726
|
-
(sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE))
|
|
727
|
-
) {
|
|
811
|
+
if (hasOrigin) {
|
|
812
|
+
if (wantJs && wantUrl) {
|
|
728
813
|
return JAVASCRIPT_AND_ASSET_URL_TYPES;
|
|
729
|
-
} else if (
|
|
814
|
+
} else if (wantUrl) {
|
|
730
815
|
return ASSET_URL_TYPES;
|
|
731
816
|
}
|
|
732
817
|
return JAVASCRIPT_TYPES;
|
|
@@ -735,13 +820,10 @@ class AssetGenerator extends Generator {
|
|
|
735
820
|
return NO_TYPES;
|
|
736
821
|
}
|
|
737
822
|
|
|
738
|
-
if (
|
|
739
|
-
if (
|
|
740
|
-
sourceTypes.has(JAVASCRIPT_TYPE) &&
|
|
741
|
-
(sourceTypes.has(CSS_TYPE) || sourceTypes.has(HTML_TYPE))
|
|
742
|
-
) {
|
|
823
|
+
if (hasOrigin) {
|
|
824
|
+
if (wantJs && wantUrl) {
|
|
743
825
|
return ASSET_AND_JAVASCRIPT_AND_ASSET_URL_TYPES;
|
|
744
|
-
} else if (
|
|
826
|
+
} else if (wantUrl) {
|
|
745
827
|
return ASSET_AND_ASSET_URL_TYPES;
|
|
746
828
|
}
|
|
747
829
|
return ASSET_AND_JAVASCRIPT_TYPES;
|
|
@@ -5,15 +5,21 @@
|
|
|
5
5
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
|
+
const { RawSource } = require("webpack-sources");
|
|
9
|
+
const HotUpdateChunk = require("../HotUpdateChunk");
|
|
8
10
|
const {
|
|
9
11
|
ASSET_MODULE_TYPE,
|
|
10
12
|
ASSET_MODULE_TYPE_BYTES,
|
|
11
13
|
ASSET_MODULE_TYPE_INLINE,
|
|
12
14
|
ASSET_MODULE_TYPE_RESOURCE,
|
|
13
|
-
ASSET_MODULE_TYPE_SOURCE
|
|
15
|
+
ASSET_MODULE_TYPE_SOURCE,
|
|
16
|
+
ASSET_MODULE_TYPE_WEBMANIFEST
|
|
14
17
|
} = require("../ModuleTypeConstants");
|
|
15
18
|
const { compareModulesByFullName } = require("../util/comparators");
|
|
19
|
+
const createHash = require("../util/createHash");
|
|
20
|
+
const { getUndoPath } = require("../util/identifier");
|
|
16
21
|
const memoize = require("../util/memoize");
|
|
22
|
+
const { PUBLIC_PATH_AUTO } = require("../util/publicPathPlaceholder");
|
|
17
23
|
|
|
18
24
|
/** @typedef {import("webpack-sources").Source} Source */
|
|
19
25
|
/** @typedef {import("schema-utils").Schema} Schema */
|
|
@@ -57,8 +63,14 @@ const getAssetSourceGenerator = memoize(() =>
|
|
|
57
63
|
);
|
|
58
64
|
const getAssetBytesGenerator = memoize(() => require("./AssetBytesGenerator"));
|
|
59
65
|
const getAssetModule = memoize(() => require("./AssetModule"));
|
|
66
|
+
const getWebManifestParser = memoize(() => require("./WebManifestParser"));
|
|
67
|
+
const getWebManifestGenerator = memoize(() =>
|
|
68
|
+
require("./WebManifestGenerator")
|
|
69
|
+
);
|
|
60
70
|
|
|
61
71
|
const type = ASSET_MODULE_TYPE;
|
|
72
|
+
// Source type produced by `WebManifestGenerator` (its emitted, rewritten JSON).
|
|
73
|
+
const WEBMANIFEST_SOURCE_TYPE = "webmanifest";
|
|
62
74
|
const PLUGIN_NAME = "AssetModulesPlugin";
|
|
63
75
|
|
|
64
76
|
/**
|
|
@@ -240,7 +252,8 @@ class AssetModulesPlugin {
|
|
|
240
252
|
filename,
|
|
241
253
|
publicPath,
|
|
242
254
|
outputPath,
|
|
243
|
-
generatorOptions.emit !== false
|
|
255
|
+
generatorOptions.emit !== false,
|
|
256
|
+
compilation
|
|
244
257
|
);
|
|
245
258
|
});
|
|
246
259
|
}
|
|
@@ -353,6 +366,83 @@ class AssetModulesPlugin {
|
|
|
353
366
|
return result;
|
|
354
367
|
});
|
|
355
368
|
|
|
369
|
+
// A Web App Manifest (`asset/webmanifest`, gated on `experiments.html`)
|
|
370
|
+
// parses/emits like an asset, but its icon URLs are rewritten in place
|
|
371
|
+
// and the emitted file needs its own per-file public-path resolution.
|
|
372
|
+
if (compilation.options.experiments.html) {
|
|
373
|
+
normalModuleFactory.hooks.createParser
|
|
374
|
+
.for(ASSET_MODULE_TYPE_WEBMANIFEST)
|
|
375
|
+
.tap(PLUGIN_NAME, () => {
|
|
376
|
+
const WebManifestParser = getWebManifestParser();
|
|
377
|
+
|
|
378
|
+
return new WebManifestParser();
|
|
379
|
+
});
|
|
380
|
+
normalModuleFactory.hooks.createGenerator
|
|
381
|
+
.for(ASSET_MODULE_TYPE_WEBMANIFEST)
|
|
382
|
+
.tap(PLUGIN_NAME, () => {
|
|
383
|
+
const WebManifestGenerator = getWebManifestGenerator();
|
|
384
|
+
|
|
385
|
+
return new WebManifestGenerator(compilation.moduleGraph);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
compilation.hooks.renderManifest.tap(
|
|
389
|
+
PLUGIN_NAME,
|
|
390
|
+
(result, options) => {
|
|
391
|
+
const { chunk, codeGenerationResults } = options;
|
|
392
|
+
if (chunk instanceof HotUpdateChunk) return result;
|
|
393
|
+
const { chunkGraph, outputOptions } = compilation;
|
|
394
|
+
const modules =
|
|
395
|
+
chunkGraph.getOrderedChunkModulesIterableBySourceType(
|
|
396
|
+
chunk,
|
|
397
|
+
WEBMANIFEST_SOURCE_TYPE,
|
|
398
|
+
compareModulesByFullName(compilation.compiler)
|
|
399
|
+
);
|
|
400
|
+
if (!modules) return result;
|
|
401
|
+
for (const module of modules) {
|
|
402
|
+
const codeGenResult = codeGenerationResults.get(
|
|
403
|
+
module,
|
|
404
|
+
chunk.runtime
|
|
405
|
+
);
|
|
406
|
+
const source = codeGenResult.sources.get(
|
|
407
|
+
WEBMANIFEST_SOURCE_TYPE
|
|
408
|
+
);
|
|
409
|
+
if (!source) continue;
|
|
410
|
+
const filename = /** @type {string} */ (
|
|
411
|
+
codeGenResult.data && codeGenResult.data.get("filename")
|
|
412
|
+
);
|
|
413
|
+
if (!filename) continue;
|
|
414
|
+
// Icon URLs resolve relative to the manifest's own location.
|
|
415
|
+
const undoPath = getUndoPath(
|
|
416
|
+
filename,
|
|
417
|
+
/** @type {string} */ (outputOptions.path),
|
|
418
|
+
false
|
|
419
|
+
);
|
|
420
|
+
const content = source
|
|
421
|
+
.source()
|
|
422
|
+
.toString()
|
|
423
|
+
.split(PUBLIC_PATH_AUTO)
|
|
424
|
+
.join(undoPath);
|
|
425
|
+
const hash = createHash(outputOptions.hashFunction || "md4");
|
|
426
|
+
hash.update(content);
|
|
427
|
+
const contentHash = /** @type {string} */ (
|
|
428
|
+
hash.digest(outputOptions.hashDigest || "hex")
|
|
429
|
+
).slice(0, outputOptions.hashDigestLength || 20);
|
|
430
|
+
result.push({
|
|
431
|
+
render: () => new RawSource(content),
|
|
432
|
+
filename,
|
|
433
|
+
info: { immutable: true },
|
|
434
|
+
auxiliary: true,
|
|
435
|
+
identifier: `webManifestModule${chunkGraph.getModuleId(
|
|
436
|
+
module
|
|
437
|
+
)}|${filename}`,
|
|
438
|
+
hash: contentHash
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
return result;
|
|
442
|
+
}
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
|
|
356
446
|
compilation.hooks.prepareModuleExecution.tap(
|
|
357
447
|
PLUGIN_NAME,
|
|
358
448
|
(options, context) => {
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
3
|
+
Author Alexander Akait @alexander-akait
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const { RawSource, ReplaceSource } = require("webpack-sources");
|
|
9
|
+
const { ASSET_URL_TYPE } = require("../ModuleSourceTypeConstants");
|
|
10
|
+
const createHash = require("../util/createHash");
|
|
11
|
+
const nonNumericOnlyHash = require("../util/nonNumericOnlyHash");
|
|
12
|
+
const { PUBLIC_PATH_AUTO } = require("../util/publicPathPlaceholder");
|
|
13
|
+
const AssetGenerator = require("./AssetGenerator");
|
|
14
|
+
|
|
15
|
+
/** @typedef {import("webpack-sources").Source} Source */
|
|
16
|
+
/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
|
|
17
|
+
/** @typedef {import("../Compilation").DependencyConstructor} DependencyConstructor */
|
|
18
|
+
/** @typedef {import("../Dependency")} Dependency */
|
|
19
|
+
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
|
|
20
|
+
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
|
21
|
+
/** @typedef {import("../Module").SourceType} SourceType */
|
|
22
|
+
/** @typedef {import("../Module").SourceTypes} SourceTypes */
|
|
23
|
+
/** @typedef {import("../ModuleGraph")} ModuleGraph */
|
|
24
|
+
/** @typedef {import("../NormalModule")} NormalModule */
|
|
25
|
+
|
|
26
|
+
const WEBMANIFEST_TYPE = "webmanifest";
|
|
27
|
+
const WEBMANIFEST_TYPES = new Set([WEBMANIFEST_TYPE]);
|
|
28
|
+
const WEBMANIFEST_AND_ASSET_URL_TYPES = new Set([
|
|
29
|
+
WEBMANIFEST_TYPE,
|
|
30
|
+
ASSET_URL_TYPE
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A Web App Manifest is a "typed asset": a variant of `AssetGenerator` (reusing
|
|
35
|
+
* its filename/hash and `ASSET_URL_TYPE` machinery) whose emitted content is the
|
|
36
|
+
* raw JSON with each icon `src` rewritten to its bundled asset URL. The manifest
|
|
37
|
+
* itself is emitted — with its own URL exposed to the referencing
|
|
38
|
+
* `<link rel="manifest">` — by `AssetModulesPlugin`'s `renderManifest`, which
|
|
39
|
+
* resolves the per-file public path (like the CSS/HTML plugins).
|
|
40
|
+
*/
|
|
41
|
+
class WebManifestGenerator extends AssetGenerator {
|
|
42
|
+
/**
|
|
43
|
+
* @param {ModuleGraph} moduleGraph the module graph
|
|
44
|
+
*/
|
|
45
|
+
constructor(moduleGraph) {
|
|
46
|
+
super(moduleGraph, undefined, undefined, undefined, undefined, true);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the source types available for this module.
|
|
51
|
+
* @param {NormalModule} module fresh module
|
|
52
|
+
* @returns {SourceTypes} available types (do not mutate)
|
|
53
|
+
*/
|
|
54
|
+
getTypes(module) {
|
|
55
|
+
// Expose the manifest's own URL only when it is referenced (from HTML).
|
|
56
|
+
const connections = this._moduleGraph.getIncomingConnections(module);
|
|
57
|
+
const referenced = !connections[Symbol.iterator]().next().done;
|
|
58
|
+
return referenced ? WEBMANIFEST_AND_ASSET_URL_TYPES : WEBMANIFEST_TYPES;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the estimated size for the requested source type.
|
|
63
|
+
* @param {NormalModule} module the module
|
|
64
|
+
* @param {SourceType=} type source type
|
|
65
|
+
* @returns {number} estimate size of the module
|
|
66
|
+
*/
|
|
67
|
+
getSize(module, type) {
|
|
68
|
+
const originalSource = module.originalSource();
|
|
69
|
+
return originalSource ? originalSource.size() : 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Rewrites each icon `src` in the raw manifest to its emitted asset URL.
|
|
74
|
+
* @param {NormalModule} module the manifest module
|
|
75
|
+
* @param {GenerateContext} generateContext context for generate
|
|
76
|
+
* @returns {string} the rewritten manifest content
|
|
77
|
+
*/
|
|
78
|
+
_rewrite(module, generateContext) {
|
|
79
|
+
const originalSource = /** @type {Source} */ (module.originalSource());
|
|
80
|
+
const source = new ReplaceSource(originalSource);
|
|
81
|
+
// `HtmlSourceDependency.Template` only reads `moduleGraph`/`runtimeTemplate`/
|
|
82
|
+
// `codeGenerationResults`; the rest is filled to satisfy the context shape.
|
|
83
|
+
/** @type {DependencyTemplateContext} */
|
|
84
|
+
const templateContext = {
|
|
85
|
+
runtimeTemplate: generateContext.runtimeTemplate,
|
|
86
|
+
dependencyTemplates: generateContext.dependencyTemplates,
|
|
87
|
+
moduleGraph: generateContext.moduleGraph,
|
|
88
|
+
chunkGraph: generateContext.chunkGraph,
|
|
89
|
+
module,
|
|
90
|
+
runtime: generateContext.runtime,
|
|
91
|
+
runtimeRequirements: generateContext.runtimeRequirements,
|
|
92
|
+
concatenationScope: generateContext.concatenationScope,
|
|
93
|
+
codeGenerationResults:
|
|
94
|
+
/** @type {CodeGenerationResults} */
|
|
95
|
+
(generateContext.codeGenerationResults),
|
|
96
|
+
initFragments: [],
|
|
97
|
+
chunkInitFragments: []
|
|
98
|
+
};
|
|
99
|
+
for (const dependency of module.dependencies) {
|
|
100
|
+
const constructor = /** @type {DependencyConstructor} */ (
|
|
101
|
+
dependency.constructor
|
|
102
|
+
);
|
|
103
|
+
const template = templateContext.dependencyTemplates.get(constructor);
|
|
104
|
+
if (!template) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
`No template for dependency: ${dependency.constructor.name}`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
template.apply(dependency, source, templateContext);
|
|
110
|
+
}
|
|
111
|
+
return /** @type {string} */ (source.source());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generates generated code for this runtime module.
|
|
116
|
+
* @param {NormalModule} module module for which the code should be generated
|
|
117
|
+
* @param {GenerateContext} generateContext context for generate
|
|
118
|
+
* @returns {Source | null} generated code
|
|
119
|
+
*/
|
|
120
|
+
generate(module, generateContext) {
|
|
121
|
+
if (!module.originalSource()) return new RawSource("");
|
|
122
|
+
|
|
123
|
+
const { type, getData } = generateContext;
|
|
124
|
+
const content = this._rewrite(module, generateContext);
|
|
125
|
+
|
|
126
|
+
// Hash the *rewritten* content (so the filename tracks the icons) and reuse
|
|
127
|
+
// the asset filename machinery, so a plain (icon-less) manifest emits like a
|
|
128
|
+
// plain asset (`output.assetModuleFilename`, `[name]`, `[ext]`).
|
|
129
|
+
const outputOptions = generateContext.runtimeTemplate.outputOptions;
|
|
130
|
+
const hash = createHash(outputOptions.hashFunction);
|
|
131
|
+
if (outputOptions.hashSalt) hash.update(outputOptions.hashSalt);
|
|
132
|
+
hash.update(content);
|
|
133
|
+
const fullContentHash = /** @type {string} */ (
|
|
134
|
+
hash.digest(outputOptions.hashDigest)
|
|
135
|
+
);
|
|
136
|
+
const contentHash = nonNumericOnlyHash(
|
|
137
|
+
fullContentHash,
|
|
138
|
+
/** @type {number} */ (outputOptions.hashDigestLength)
|
|
139
|
+
);
|
|
140
|
+
const { filename, assetInfo } = AssetGenerator.getFilenameWithInfo(
|
|
141
|
+
module,
|
|
142
|
+
{ filename: undefined, outputPath: undefined },
|
|
143
|
+
generateContext,
|
|
144
|
+
contentHash,
|
|
145
|
+
fullContentHash
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const data = getData ? getData() : undefined;
|
|
149
|
+
if (data) {
|
|
150
|
+
data.set("filename", filename);
|
|
151
|
+
data.set("assetInfo", assetInfo);
|
|
152
|
+
if (type === ASSET_URL_TYPE) {
|
|
153
|
+
data.set("url", {
|
|
154
|
+
...data.get("url"),
|
|
155
|
+
[ASSET_URL_TYPE]: PUBLIC_PATH_AUTO + filename
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return type === ASSET_URL_TYPE ? null : new RawSource(content);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = WebManifestGenerator;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/*
|
|
2
|
+
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
3
|
+
Author Alexander Akait @alexander-akait
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
"use strict";
|
|
7
|
+
|
|
8
|
+
const { parse } = require("acorn");
|
|
9
|
+
const Parser = require("../Parser");
|
|
10
|
+
const HtmlSourceDependency = require("../dependencies/HtmlSourceDependency");
|
|
11
|
+
|
|
12
|
+
/** @typedef {import("estree").Expression} Expression */
|
|
13
|
+
/** @typedef {import("estree").ObjectExpression} ObjectExpression */
|
|
14
|
+
/** @typedef {import("estree").Program} Program */
|
|
15
|
+
/** @typedef {import("estree").Property} Property */
|
|
16
|
+
/** @typedef {import("../Module").BuildInfo} BuildInfo */
|
|
17
|
+
/** @typedef {import("../Parser").ParserState} ParserState */
|
|
18
|
+
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
|
|
19
|
+
|
|
20
|
+
// acorn decorates every node with numeric source offsets (absent from the estree types).
|
|
21
|
+
/** @typedef {{ start: number, end: number }} Positioned */
|
|
22
|
+
|
|
23
|
+
// A URL carrying its own scheme (`https:`, `data:`, …) is external; it is only
|
|
24
|
+
// bundled when `experiments.buildHttp` is enabled (like an absolute URL in HTML).
|
|
25
|
+
const ABSOLUTE_URL_SCHEME_REGEXP = /^[a-zA-Z][a-zA-Z\d+\-.]*:/;
|
|
26
|
+
// Manifest members whose array items carry an asset `src` (`icons[].src`,
|
|
27
|
+
// `screenshots[].src`, and `shortcuts[].icons[].src` — the last nests under `icons`).
|
|
28
|
+
const ICON_CONTAINER_KEYS = new Set(["icons", "screenshots"]);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parses a Web App Manifest (`.webmanifest`) so its icon/screenshot `src`
|
|
32
|
+
* URLs are bundled as assets. Reuses acorn (JSON is a valid JS expression
|
|
33
|
+
* literal) to recover the exact source offsets, then emits an
|
|
34
|
+
* `HtmlSourceDependency` per URL so the generator can rewrite it in place.
|
|
35
|
+
*/
|
|
36
|
+
class WebManifestParser extends Parser {
|
|
37
|
+
/**
|
|
38
|
+
* Parses the provided source and updates the parser state.
|
|
39
|
+
* @param {string | Buffer | PreparsedAst} source the source to parse
|
|
40
|
+
* @param {ParserState} state the parser state
|
|
41
|
+
* @returns {ParserState} the parser state
|
|
42
|
+
*/
|
|
43
|
+
parse(source, state) {
|
|
44
|
+
if (Buffer.isBuffer(source)) {
|
|
45
|
+
source = source.toString("utf8");
|
|
46
|
+
} else if (typeof source === "object") {
|
|
47
|
+
throw new Error("webpackAst is unexpected for the WebManifestParser");
|
|
48
|
+
}
|
|
49
|
+
if (source[0] === "") {
|
|
50
|
+
source = source.slice(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const module = state.module;
|
|
54
|
+
// Without `buildHttp` there is no handler to fetch remote icons, so an
|
|
55
|
+
// absolute URL is left as-is rather than rewritten to an ignored asset.
|
|
56
|
+
const buildHttp = Boolean(state.options.experiments.buildHttp);
|
|
57
|
+
|
|
58
|
+
/** @type {Program | undefined} */
|
|
59
|
+
let ast;
|
|
60
|
+
try {
|
|
61
|
+
// Wrap in parens so the top-level object is an expression, not a block.
|
|
62
|
+
ast = /** @type {Program} */ (
|
|
63
|
+
/** @type {unknown} */ (parse(`(${source})`, { ecmaVersion: "latest" }))
|
|
64
|
+
);
|
|
65
|
+
} catch (_err) {
|
|
66
|
+
// Not valid JSON — leave the file untouched (still emitted as-is).
|
|
67
|
+
ast = undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const statement = ast && ast.body[0];
|
|
71
|
+
if (
|
|
72
|
+
statement &&
|
|
73
|
+
statement.type === "ExpressionStatement" &&
|
|
74
|
+
statement.expression.type === "ObjectExpression"
|
|
75
|
+
) {
|
|
76
|
+
/**
|
|
77
|
+
* @param {ObjectExpression} obj object expression node
|
|
78
|
+
* @param {string | undefined} parentKey key of the array/object this node sits in
|
|
79
|
+
*/
|
|
80
|
+
const walk = (obj, parentKey) => {
|
|
81
|
+
for (const prop of obj.properties) {
|
|
82
|
+
if (prop.type !== "Property") continue;
|
|
83
|
+
const key =
|
|
84
|
+
prop.key.type === "Literal" && typeof prop.key.value === "string"
|
|
85
|
+
? prop.key.value
|
|
86
|
+
: prop.key.type === "Identifier"
|
|
87
|
+
? prop.key.name
|
|
88
|
+
: undefined;
|
|
89
|
+
const value = /** @type {Expression} */ (prop.value);
|
|
90
|
+
if (value.type === "ObjectExpression") {
|
|
91
|
+
walk(value, key);
|
|
92
|
+
} else if (value.type === "ArrayExpression") {
|
|
93
|
+
for (const element of value.elements) {
|
|
94
|
+
if (element && element.type === "ObjectExpression") {
|
|
95
|
+
walk(element, key);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} else if (
|
|
99
|
+
key === "src" &&
|
|
100
|
+
value.type === "Literal" &&
|
|
101
|
+
typeof value.value === "string" &&
|
|
102
|
+
parentKey !== undefined &&
|
|
103
|
+
ICON_CONTAINER_KEYS.has(parentKey)
|
|
104
|
+
) {
|
|
105
|
+
const url = value.value;
|
|
106
|
+
// Fragment-only refs aren't assets; absolute URLs need `buildHttp`.
|
|
107
|
+
if (!url || url.startsWith("#")) continue;
|
|
108
|
+
if (!buildHttp && ABSOLUTE_URL_SCHEME_REGEXP.test(url)) continue;
|
|
109
|
+
// acorn offsets are into `(${source})`; the leading `(` and the
|
|
110
|
+
// opening quote cancel, so the inner span is [start, end - 2].
|
|
111
|
+
const { start, end } = /** @type {Positioned} */ (
|
|
112
|
+
/** @type {unknown} */ (value)
|
|
113
|
+
);
|
|
114
|
+
const dep = new HtmlSourceDependency(url, [start, end - 2]);
|
|
115
|
+
module.addDependency(dep);
|
|
116
|
+
module.addCodeGenerationDependency(dep);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
walk(statement.expression, undefined);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @type {BuildInfo} */
|
|
124
|
+
(state.module.buildInfo).strict = true;
|
|
125
|
+
|
|
126
|
+
return state;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = WebManifestParser;
|