mirror of https://github.com/webpack/webpack.git
Merge a8d39c0cdf
into 3c08fd105c
This commit is contained in:
commit
eaa44e9de2
|
@ -90,6 +90,7 @@
|
||||||
"externref",
|
"externref",
|
||||||
"fetchpriority",
|
"fetchpriority",
|
||||||
"filebase",
|
"filebase",
|
||||||
|
"flac",
|
||||||
"fileoverview",
|
"fileoverview",
|
||||||
"filepath",
|
"filepath",
|
||||||
"finalizer",
|
"finalizer",
|
||||||
|
|
|
@ -312,6 +312,11 @@ module.exports.nodeModuleDecorator = "__webpack_require__.nmd";
|
||||||
*/
|
*/
|
||||||
module.exports.onChunksLoaded = "__webpack_require__.O";
|
module.exports.onChunksLoaded = "__webpack_require__.O";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the asset prefetch function
|
||||||
|
*/
|
||||||
|
module.exports.prefetchAsset = "__webpack_require__.PA";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the chunk prefetch function
|
* the chunk prefetch function
|
||||||
*/
|
*/
|
||||||
|
@ -322,6 +327,11 @@ module.exports.prefetchChunk = "__webpack_require__.E";
|
||||||
*/
|
*/
|
||||||
module.exports.prefetchChunkHandlers = "__webpack_require__.F";
|
module.exports.prefetchChunkHandlers = "__webpack_require__.F";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the asset preload function
|
||||||
|
*/
|
||||||
|
module.exports.preloadAsset = "__webpack_require__.LA";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the chunk preload function
|
* the chunk preload function
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,6 +34,8 @@ const WebpackIsIncludedPlugin = require("./WebpackIsIncludedPlugin");
|
||||||
|
|
||||||
const AssetModulesPlugin = require("./asset/AssetModulesPlugin");
|
const AssetModulesPlugin = require("./asset/AssetModulesPlugin");
|
||||||
|
|
||||||
|
const AssetResourcePrefetchPlugin = require("./asset/AssetResourcePrefetchPlugin");
|
||||||
|
|
||||||
const InferAsyncModulesPlugin = require("./async-modules/InferAsyncModulesPlugin");
|
const InferAsyncModulesPlugin = require("./async-modules/InferAsyncModulesPlugin");
|
||||||
|
|
||||||
const ResolverCachePlugin = require("./cache/ResolverCachePlugin");
|
const ResolverCachePlugin = require("./cache/ResolverCachePlugin");
|
||||||
|
@ -200,6 +202,21 @@ class WebpackOptionsApply extends OptionsApply {
|
||||||
|
|
||||||
new ChunkPrefetchPreloadPlugin().apply(compiler);
|
new ChunkPrefetchPreloadPlugin().apply(compiler);
|
||||||
|
|
||||||
|
// Apply AssetResourcePrefetchPlugin only for web targets or universal targets
|
||||||
|
// Check if we're targeting web environment
|
||||||
|
const externalsPresets = options.externalsPresets || {};
|
||||||
|
const isTargetingWeb = Boolean(
|
||||||
|
externalsPresets.web ||
|
||||||
|
externalsPresets.webAsync ||
|
||||||
|
externalsPresets.electronRenderer
|
||||||
|
);
|
||||||
|
|
||||||
|
// Apply the plugin if we're targeting web environment
|
||||||
|
// For universal targets (["web", "node"]), the runtime module will handle platform detection using isNeutralPlatform
|
||||||
|
if (isTargetingWeb || !externalsPresets.node) {
|
||||||
|
new AssetResourcePrefetchPlugin().apply(compiler);
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof options.output.chunkFormat === "string") {
|
if (typeof options.output.chunkFormat === "string") {
|
||||||
switch (options.output.chunkFormat) {
|
switch (options.output.chunkFormat) {
|
||||||
case "array-push": {
|
case "array-push": {
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
Author Tobias Koppers @sokra
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
|
const ResourcePrefetchRuntimeModule = require("../prefetch/ResourcePrefetchRuntimeModule");
|
||||||
|
|
||||||
|
/** @typedef {import("../Compiler")} Compiler */
|
||||||
|
|
||||||
|
const PLUGIN_NAME = "AssetResourcePrefetchPlugin";
|
||||||
|
|
||||||
|
class AssetResourcePrefetchPlugin {
|
||||||
|
/**
|
||||||
|
* @param {Compiler} compiler the compiler
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
apply(compiler) {
|
||||||
|
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
||||||
|
// prefetchAsset
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.prefetchAsset)
|
||||||
|
.tap(PLUGIN_NAME, (chunk, set) => {
|
||||||
|
set.add(RuntimeGlobals.publicPath);
|
||||||
|
set.add(RuntimeGlobals.require);
|
||||||
|
set.add(RuntimeGlobals.baseURI);
|
||||||
|
set.add(RuntimeGlobals.relativeUrl);
|
||||||
|
compilation.addRuntimeModule(
|
||||||
|
chunk,
|
||||||
|
new ResourcePrefetchRuntimeModule("prefetch")
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// preloadAsset
|
||||||
|
compilation.hooks.runtimeRequirementInTree
|
||||||
|
.for(RuntimeGlobals.preloadAsset)
|
||||||
|
.tap(PLUGIN_NAME, (chunk, set) => {
|
||||||
|
set.add(RuntimeGlobals.publicPath);
|
||||||
|
set.add(RuntimeGlobals.require);
|
||||||
|
set.add(RuntimeGlobals.baseURI);
|
||||||
|
set.add(RuntimeGlobals.relativeUrl);
|
||||||
|
compilation.addRuntimeModule(
|
||||||
|
chunk,
|
||||||
|
new ResourcePrefetchRuntimeModule("preload")
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AssetResourcePrefetchPlugin;
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const InitFragment = require("../InitFragment");
|
||||||
const RuntimeGlobals = require("../RuntimeGlobals");
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
const RawDataUrlModule = require("../asset/RawDataUrlModule");
|
const RawDataUrlModule = require("../asset/RawDataUrlModule");
|
||||||
const {
|
const {
|
||||||
|
@ -43,6 +44,15 @@ class URLDependency extends ModuleDependency {
|
||||||
this.relative = relative || false;
|
this.relative = relative || false;
|
||||||
/** @type {UsedByExports | undefined} */
|
/** @type {UsedByExports | undefined} */
|
||||||
this.usedByExports = undefined;
|
this.usedByExports = undefined;
|
||||||
|
this.prefetch = undefined;
|
||||||
|
this.preload = undefined;
|
||||||
|
this.fetchPriority = undefined;
|
||||||
|
/** @type {string|undefined} */
|
||||||
|
this.preloadAs = undefined;
|
||||||
|
/** @type {string|undefined} */
|
||||||
|
this.preloadType = undefined;
|
||||||
|
/** @type {string|undefined} */
|
||||||
|
this.preloadMedia = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
get type() {
|
get type() {
|
||||||
|
@ -81,6 +91,12 @@ class URLDependency extends ModuleDependency {
|
||||||
write(this.outerRange);
|
write(this.outerRange);
|
||||||
write(this.relative);
|
write(this.relative);
|
||||||
write(this.usedByExports);
|
write(this.usedByExports);
|
||||||
|
write(this.prefetch);
|
||||||
|
write(this.preload);
|
||||||
|
write(this.fetchPriority);
|
||||||
|
write(this.preloadAs);
|
||||||
|
write(this.preloadType);
|
||||||
|
write(this.preloadMedia);
|
||||||
super.serialize(context);
|
super.serialize(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +108,12 @@ class URLDependency extends ModuleDependency {
|
||||||
this.outerRange = read();
|
this.outerRange = read();
|
||||||
this.relative = read();
|
this.relative = read();
|
||||||
this.usedByExports = read();
|
this.usedByExports = read();
|
||||||
|
this.prefetch = read();
|
||||||
|
this.preload = read();
|
||||||
|
this.fetchPriority = read();
|
||||||
|
this.preloadAs = read();
|
||||||
|
this.preloadType = read();
|
||||||
|
this.preloadMedia = read();
|
||||||
super.deserialize(context);
|
super.deserialize(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +121,32 @@ class URLDependency extends ModuleDependency {
|
||||||
URLDependency.Template = class URLDependencyTemplate extends (
|
URLDependency.Template = class URLDependencyTemplate extends (
|
||||||
ModuleDependency.Template
|
ModuleDependency.Template
|
||||||
) {
|
) {
|
||||||
|
/**
|
||||||
|
* Determines the 'as' attribute value for prefetch/preload based on file extension
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload#what_types_of_content_can_be_preloaded
|
||||||
|
* @param {string} request module request string or filename
|
||||||
|
* @returns {string} asset type for link element 'as' attribute
|
||||||
|
*/
|
||||||
|
static _getAssetType(request) {
|
||||||
|
if (/\.(png|jpe?g|gif|svg|webp|avif|bmp|ico|tiff?)$/i.test(request)) {
|
||||||
|
return "image";
|
||||||
|
} else if (/\.(woff2?|ttf|otf|eot)$/i.test(request)) {
|
||||||
|
return "font";
|
||||||
|
} else if (/\.(js|mjs|jsx|ts|tsx)$/i.test(request)) {
|
||||||
|
return "script";
|
||||||
|
} else if (/\.css$/i.test(request)) {
|
||||||
|
return "style";
|
||||||
|
} else if (/\.vtt$/i.test(request)) {
|
||||||
|
return "track";
|
||||||
|
} else if (
|
||||||
|
/\.(mp4|webm|ogg|mp3|wav|flac|aac|m4a|avi|mov|wmv|mkv)$/i.test(request)
|
||||||
|
) {
|
||||||
|
// Audio/video files use 'fetch' as browser support varies
|
||||||
|
return "fetch";
|
||||||
|
}
|
||||||
|
return "fetch";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Dependency} dependency the dependency for which the template should be applied
|
* @param {Dependency} dependency the dependency for which the template should be applied
|
||||||
* @param {ReplaceSource} source the current replace source which can be modified
|
* @param {ReplaceSource} source the current replace source which can be modified
|
||||||
|
@ -111,9 +159,12 @@ URLDependency.Template = class URLDependencyTemplate extends (
|
||||||
moduleGraph,
|
moduleGraph,
|
||||||
runtimeRequirements,
|
runtimeRequirements,
|
||||||
runtimeTemplate,
|
runtimeTemplate,
|
||||||
runtime
|
runtime,
|
||||||
|
initFragments
|
||||||
} = templateContext;
|
} = templateContext;
|
||||||
const dep = /** @type {URLDependency} */ (dependency);
|
const dep = /** @type {URLDependency} */ (dependency);
|
||||||
|
|
||||||
|
const module = moduleGraph.getModule(dep);
|
||||||
const connection = moduleGraph.getConnection(dep);
|
const connection = moduleGraph.getConnection(dep);
|
||||||
// Skip rendering depending when dependency is conditional
|
// Skip rendering depending when dependency is conditional
|
||||||
if (connection && !connection.isTargetActive(runtime)) {
|
if (connection && !connection.isTargetActive(runtime)) {
|
||||||
|
@ -125,38 +176,87 @@ URLDependency.Template = class URLDependencyTemplate extends (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimeRequirements.add(RuntimeGlobals.require);
|
// Standard URL generation
|
||||||
|
|
||||||
if (dep.relative) {
|
if (dep.relative) {
|
||||||
runtimeRequirements.add(RuntimeGlobals.relativeUrl);
|
runtimeRequirements.add(RuntimeGlobals.relativeUrl);
|
||||||
source.replace(
|
source.replace(
|
||||||
dep.outerRange[0],
|
dep.outerRange[0],
|
||||||
dep.outerRange[1] - 1,
|
dep.outerRange[1] - 1,
|
||||||
`/* asset import */ new ${
|
`/* asset import */ new ${RuntimeGlobals.relativeUrl}(${runtimeTemplate.moduleRaw(
|
||||||
RuntimeGlobals.relativeUrl
|
{
|
||||||
}(${runtimeTemplate.moduleRaw({
|
chunkGraph,
|
||||||
chunkGraph,
|
module,
|
||||||
module: moduleGraph.getModule(dep),
|
request: dep.request,
|
||||||
request: dep.request,
|
runtimeRequirements,
|
||||||
runtimeRequirements,
|
weak: false
|
||||||
weak: false
|
}
|
||||||
})})`
|
)})`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
runtimeRequirements.add(RuntimeGlobals.baseURI);
|
runtimeRequirements.add(RuntimeGlobals.baseURI);
|
||||||
|
|
||||||
source.replace(
|
source.replace(
|
||||||
dep.range[0],
|
dep.range[0],
|
||||||
dep.range[1] - 1,
|
dep.range[1] - 1,
|
||||||
`/* asset import */ ${runtimeTemplate.moduleRaw({
|
`/* asset import */ ${runtimeTemplate.moduleRaw({
|
||||||
chunkGraph,
|
chunkGraph,
|
||||||
module: moduleGraph.getModule(dep),
|
module,
|
||||||
request: dep.request,
|
request: dep.request,
|
||||||
runtimeRequirements,
|
runtimeRequirements,
|
||||||
weak: false
|
weak: false
|
||||||
})}, ${RuntimeGlobals.baseURI}`
|
})}, ${RuntimeGlobals.baseURI}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefetch/Preload via InitFragment
|
||||||
|
if ((dep.prefetch || dep.preload) && module) {
|
||||||
|
const request = dep.request;
|
||||||
|
const detectedAssetType = URLDependencyTemplate._getAssetType(request);
|
||||||
|
const id = chunkGraph.getModuleId(module);
|
||||||
|
if (id !== null) {
|
||||||
|
const moduleId = runtimeTemplate.moduleId({
|
||||||
|
module,
|
||||||
|
chunkGraph,
|
||||||
|
request: dep.request,
|
||||||
|
weak: false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (dep.preload) {
|
||||||
|
runtimeRequirements.add(RuntimeGlobals.preloadAsset);
|
||||||
|
const asArg = JSON.stringify(dep.preloadAs || detectedAssetType);
|
||||||
|
const fetchPriorityArg = dep.fetchPriority
|
||||||
|
? JSON.stringify(dep.fetchPriority)
|
||||||
|
: "undefined";
|
||||||
|
const typeArg = dep.preloadType
|
||||||
|
? JSON.stringify(dep.preloadType)
|
||||||
|
: "undefined";
|
||||||
|
const mediaArg = dep.preloadMedia
|
||||||
|
? JSON.stringify(dep.preloadMedia)
|
||||||
|
: "undefined";
|
||||||
|
initFragments.push(
|
||||||
|
new InitFragment(
|
||||||
|
`${RuntimeGlobals.preloadAsset}(${moduleId}, ${asArg}, ${fetchPriorityArg}, ${typeArg}, ${mediaArg}, ${dep.relative});\n`,
|
||||||
|
InitFragment.STAGE_CONSTANTS,
|
||||||
|
-10,
|
||||||
|
`asset_preload_${moduleId}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else if (dep.prefetch) {
|
||||||
|
runtimeRequirements.add(RuntimeGlobals.prefetchAsset);
|
||||||
|
const asArg = JSON.stringify(detectedAssetType);
|
||||||
|
const fetchPriorityArg = dep.fetchPriority
|
||||||
|
? JSON.stringify(dep.fetchPriority)
|
||||||
|
: "undefined";
|
||||||
|
initFragments.push(
|
||||||
|
new InitFragment(
|
||||||
|
`${RuntimeGlobals.prefetchAsset}(${moduleId}, ${asArg}, ${fetchPriorityArg}, undefined, undefined, ${dep.relative});\n`,
|
||||||
|
InitFragment.STAGE_CONSTANTS,
|
||||||
|
-5,
|
||||||
|
`asset_prefetch_${moduleId}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ const WorkerDependency = require("./WorkerDependency");
|
||||||
/** @typedef {import("../../declarations/WebpackOptions").WasmLoading} WasmLoading */
|
/** @typedef {import("../../declarations/WebpackOptions").WasmLoading} WasmLoading */
|
||||||
/** @typedef {import("../../declarations/WebpackOptions").WorkerPublicPath} WorkerPublicPath */
|
/** @typedef {import("../../declarations/WebpackOptions").WorkerPublicPath} WorkerPublicPath */
|
||||||
/** @typedef {import("../Compiler")} Compiler */
|
/** @typedef {import("../Compiler")} Compiler */
|
||||||
|
/** @typedef {import("../ChunkGroup").RawChunkGroupOptions} RawChunkGroupOptions */
|
||||||
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
|
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
|
||||||
/** @typedef {import("../Entrypoint").EntryOptions} EntryOptions */
|
/** @typedef {import("../Entrypoint").EntryOptions} EntryOptions */
|
||||||
/** @typedef {import("../NormalModule")} NormalModule */
|
/** @typedef {import("../NormalModule")} NormalModule */
|
||||||
|
@ -223,9 +224,12 @@ class WorkerPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const insertType = expr.properties.length > 0 ? "comma" : "single";
|
const insertType = expr.properties.length > 0 ? "comma" : "single";
|
||||||
const insertLocation = /** @type {Range} */ (
|
const insertLocation =
|
||||||
expr.properties[expr.properties.length - 1].range
|
expr.properties.length > 0
|
||||||
)[1];
|
? /** @type {Range} */ (
|
||||||
|
expr.properties[expr.properties.length - 1].range
|
||||||
|
)[1]
|
||||||
|
: /** @type {Range} */ (expr.range)[0] + 1;
|
||||||
return {
|
return {
|
||||||
expressions,
|
expressions,
|
||||||
otherElements,
|
otherElements,
|
||||||
|
@ -299,6 +303,10 @@ class WorkerPlugin {
|
||||||
? /** @type {Range} */ (arg2.range)
|
? /** @type {Range} */ (arg2.range)
|
||||||
: /** @type {Range} */ (arg1.range)[1]
|
: /** @type {Range} */ (arg1.range)[1]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @type {RawChunkGroupOptions} */
|
||||||
|
const groupOptions = {};
|
||||||
|
|
||||||
const { options: importOptions, errors: commentErrors } =
|
const { options: importOptions, errors: commentErrors } =
|
||||||
parser.parseCommentOptions(/** @type {Range} */ (expr.range));
|
parser.parseCommentOptions(/** @type {Range} */ (expr.range));
|
||||||
|
|
||||||
|
@ -360,6 +368,60 @@ class WorkerPlugin {
|
||||||
entryOptions.name = importOptions.webpackChunkName;
|
entryOptions.name = importOptions.webpackChunkName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Support webpackPrefetch (true | number)
|
||||||
|
if (importOptions.webpackPrefetch !== undefined) {
|
||||||
|
if (importOptions.webpackPrefetch === true) {
|
||||||
|
groupOptions.prefetchOrder = 0;
|
||||||
|
} else if (typeof importOptions.webpackPrefetch === "number") {
|
||||||
|
groupOptions.prefetchOrder = importOptions.webpackPrefetch;
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPrefetch\` expected true or a number, but received: ${importOptions.webpackPrefetch}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support webpackPreload (true | number)
|
||||||
|
if (importOptions.webpackPreload !== undefined) {
|
||||||
|
if (importOptions.webpackPreload === true) {
|
||||||
|
groupOptions.preloadOrder = 0;
|
||||||
|
} else if (typeof importOptions.webpackPreload === "number") {
|
||||||
|
groupOptions.preloadOrder = importOptions.webpackPreload;
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPreload\` expected true or a number, but received: ${importOptions.webpackPreload}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support webpackFetchPriority ("high" | "low" | "auto")
|
||||||
|
if (importOptions.webpackFetchPriority !== undefined) {
|
||||||
|
if (
|
||||||
|
typeof importOptions.webpackFetchPriority === "string" &&
|
||||||
|
["high", "low", "auto"].includes(
|
||||||
|
importOptions.webpackFetchPriority
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
groupOptions.fetchPriority =
|
||||||
|
/** @type {"auto" | "high" | "low"} */ (
|
||||||
|
importOptions.webpackFetchPriority
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackFetchPriority\` expected "low", "high" or "auto", but received: ${importOptions.webpackFetchPriority}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -388,6 +450,7 @@ class WorkerPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
const block = new AsyncDependenciesBlock({
|
const block = new AsyncDependenciesBlock({
|
||||||
|
...groupOptions,
|
||||||
name: entryOptions.name,
|
name: entryOptions.name,
|
||||||
entryOptions: {
|
entryOptions: {
|
||||||
chunkLoading: this._chunkLoading,
|
chunkLoading: this._chunkLoading,
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||||
|
Author Tobias Koppers @sokra
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||||
|
const RuntimeModule = require("../RuntimeModule");
|
||||||
|
const Template = require("../Template");
|
||||||
|
|
||||||
|
/** @typedef {import("../Compilation")} Compilation */
|
||||||
|
|
||||||
|
class ResourcePrefetchRuntimeModule extends RuntimeModule {
|
||||||
|
/**
|
||||||
|
* @param {string} type "prefetch" or "preload"
|
||||||
|
*/
|
||||||
|
constructor(type) {
|
||||||
|
super(`asset ${type}`, RuntimeModule.STAGE_ATTACH);
|
||||||
|
this._type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string | null} runtime code
|
||||||
|
*/
|
||||||
|
generate() {
|
||||||
|
const { compilation } = this;
|
||||||
|
if (!compilation) return null;
|
||||||
|
|
||||||
|
const { runtimeTemplate, outputOptions } = compilation;
|
||||||
|
const fnName =
|
||||||
|
this._type === "prefetch"
|
||||||
|
? RuntimeGlobals.prefetchAsset
|
||||||
|
: RuntimeGlobals.preloadAsset;
|
||||||
|
|
||||||
|
const crossOriginLoading = outputOptions.crossOriginLoading;
|
||||||
|
const isNeutralPlatform = runtimeTemplate.isNeutralPlatform();
|
||||||
|
|
||||||
|
// For neutral platform (universal targets), generate code that checks for document at runtime
|
||||||
|
const code = [
|
||||||
|
"var url;",
|
||||||
|
"if (relative) {",
|
||||||
|
Template.indent([
|
||||||
|
`url = new ${RuntimeGlobals.relativeUrl}(${RuntimeGlobals.require}(moduleId));`
|
||||||
|
]),
|
||||||
|
"} else {",
|
||||||
|
Template.indent([
|
||||||
|
`url = new URL(${RuntimeGlobals.require}(moduleId), ${RuntimeGlobals.baseURI});`
|
||||||
|
]),
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
"var link = document.createElement('link');",
|
||||||
|
`link.rel = '${this._type}';`,
|
||||||
|
"if (as) link.as = as;",
|
||||||
|
"link.href = url.href;",
|
||||||
|
"",
|
||||||
|
"if (fetchPriority) {",
|
||||||
|
Template.indent([
|
||||||
|
"link.fetchPriority = fetchPriority;",
|
||||||
|
"link.setAttribute('fetchpriority', fetchPriority);"
|
||||||
|
]),
|
||||||
|
"}",
|
||||||
|
"",
|
||||||
|
"if (type) link.type = type;",
|
||||||
|
"if (media) link.media = media;",
|
||||||
|
"",
|
||||||
|
crossOriginLoading
|
||||||
|
? Template.asString([
|
||||||
|
"if (link.href.indexOf(window.location.origin + '/') !== 0) {",
|
||||||
|
Template.indent([
|
||||||
|
`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
|
||||||
|
]),
|
||||||
|
"}"
|
||||||
|
])
|
||||||
|
: "",
|
||||||
|
"",
|
||||||
|
"document.head.appendChild(link);"
|
||||||
|
];
|
||||||
|
|
||||||
|
// For neutral platform, wrap the code to check for document availability
|
||||||
|
if (isNeutralPlatform) {
|
||||||
|
return Template.asString([
|
||||||
|
`${fnName} = ${runtimeTemplate.basicFunction(
|
||||||
|
"moduleId, as, fetchPriority, type, media, relative",
|
||||||
|
[
|
||||||
|
"// Only execute in browser environment",
|
||||||
|
"if (typeof document !== 'undefined') {",
|
||||||
|
Template.indent(code),
|
||||||
|
"}"
|
||||||
|
]
|
||||||
|
)};`
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For browser-only targets, generate code without the check
|
||||||
|
return Template.asString([
|
||||||
|
`${fnName} = ${runtimeTemplate.basicFunction(
|
||||||
|
"moduleId, as, fetchPriority, type, media, relative",
|
||||||
|
code
|
||||||
|
)};`
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ResourcePrefetchRuntimeModule;
|
|
@ -182,6 +182,91 @@ class URLParserPlugin {
|
||||||
relative
|
relative
|
||||||
);
|
);
|
||||||
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
|
dep.loc = /** @type {DependencyLocation} */ (expr.loc);
|
||||||
|
// Parse magic comments with simplified rules
|
||||||
|
if (importOptions) {
|
||||||
|
// Accept only boolean true for webpackPrefetch
|
||||||
|
if (importOptions.webpackPrefetch === true) {
|
||||||
|
dep.prefetch = true;
|
||||||
|
} else if (importOptions.webpackPrefetch !== undefined) {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPrefetch\` expected true, but received: ${importOptions.webpackPrefetch}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept only boolean true for webpackPreload
|
||||||
|
if (importOptions.webpackPreload === true) {
|
||||||
|
dep.preload = true;
|
||||||
|
} else if (importOptions.webpackPreload !== undefined) {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPreload\` expected true, but received: ${importOptions.webpackPreload}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// webpackFetchPriority: "high" | "low" | "auto"
|
||||||
|
if (
|
||||||
|
typeof importOptions.webpackFetchPriority === "string" &&
|
||||||
|
["high", "low", "auto"].includes(importOptions.webpackFetchPriority)
|
||||||
|
) {
|
||||||
|
dep.fetchPriority = importOptions.webpackFetchPriority;
|
||||||
|
} else if (importOptions.webpackFetchPriority !== undefined) {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackFetchPriority\` expected "low", "high" or "auto", but received: ${importOptions.webpackFetchPriority}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// webpackPreloadAs: allow override of the "as" attribute for preload
|
||||||
|
if (importOptions.webpackPreloadAs !== undefined) {
|
||||||
|
if (typeof importOptions.webpackPreloadAs === "string") {
|
||||||
|
dep.preloadAs = importOptions.webpackPreloadAs;
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPreloadAs\` expected a string, but received: ${importOptions.webpackPreloadAs}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// webpackPreloadType: set link.type when provided
|
||||||
|
if (importOptions.webpackPreloadType !== undefined) {
|
||||||
|
if (typeof importOptions.webpackPreloadType === "string") {
|
||||||
|
dep.preloadType = importOptions.webpackPreloadType;
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPreloadType\` expected a string, but received: ${importOptions.webpackPreloadType}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// webpackPreloadMedia: set link.media when provided
|
||||||
|
if (importOptions.webpackPreloadMedia !== undefined) {
|
||||||
|
if (typeof importOptions.webpackPreloadMedia === "string") {
|
||||||
|
dep.preloadMedia = importOptions.webpackPreloadMedia;
|
||||||
|
} else {
|
||||||
|
parser.state.module.addWarning(
|
||||||
|
new UnsupportedFeatureWarning(
|
||||||
|
`\`webpackPreloadMedia\` expected a string, but received: ${importOptions.webpackPreloadMedia}.`,
|
||||||
|
/** @type {DependencyLocation} */ (expr.loc)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the dependency
|
||||||
parser.state.current.addDependency(dep);
|
parser.state.current.addDependency(dep);
|
||||||
InnerGraph.onUsage(parser.state, (e) => (dep.usedByExports = e));
|
InnerGraph.onUsage(parser.state, (e) => (dep.usedByExports = e));
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
.typed-element {
|
||||||
|
color: #333;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// This file is used to generate expected warnings during compilation
|
||||||
|
|
||||||
|
// Invalid fetchPriority value - should generate warning
|
||||||
|
const invalidPriorityUrl = new URL(/* webpackPrefetch: true */ /* webpackFetchPriority: "invalid" */ "./assets/images/priority-invalid.png", import.meta.url);
|
||||||
|
// Invalid preloadAs (non-string) - should generate warning
|
||||||
|
const invalidPreloadAs = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackPreloadAs: 123 */
|
||||||
|
"./assets/images/priority-invalid.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
// Invalid preloadType (non-string) - should generate warning
|
||||||
|
const invalidPreloadType = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackPreloadType: 123 */
|
||||||
|
"./assets/images/priority-invalid.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
|
||||||
|
// Invalid preloadMedia (non-string) - should generate warning
|
||||||
|
const invalidPreloadMedia = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackPreloadMedia: 456 */
|
||||||
|
"./assets/images/priority-invalid.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
|
||||||
|
export default {};
|
|
@ -0,0 +1,178 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function verifyLink(link, expectations) {
|
||||||
|
expect(link._type).toBe("link");
|
||||||
|
expect(link.rel).toBe(expectations.rel);
|
||||||
|
|
||||||
|
if (expectations.as) {
|
||||||
|
expect(link.as).toBe(expectations.as);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectations.type !== undefined) {
|
||||||
|
if (expectations.type) {
|
||||||
|
expect(link.type).toBe(expectations.type);
|
||||||
|
} else {
|
||||||
|
expect(link.type).toBeUndefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectations.media !== undefined) {
|
||||||
|
if (expectations.media) {
|
||||||
|
expect(link.media).toBe(expectations.media);
|
||||||
|
} else {
|
||||||
|
expect(link.media).toBeUndefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectations.fetchPriority !== undefined) {
|
||||||
|
if (expectations.fetchPriority) {
|
||||||
|
expect(link._attributes.fetchpriority).toBe(expectations.fetchPriority);
|
||||||
|
expect(link.fetchPriority).toBe(expectations.fetchPriority);
|
||||||
|
} else {
|
||||||
|
expect(link._attributes.fetchpriority).toBeUndefined();
|
||||||
|
expect(link.fetchPriority).toBeUndefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (expectations.href) {
|
||||||
|
expect(link.href.toString()).toMatch(expectations.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should generate all prefetch and preload links", () => {
|
||||||
|
const urls = {
|
||||||
|
prefetchHigh: new URL(
|
||||||
|
/* webpackPrefetch: true */ /* webpackFetchPriority: "high" */
|
||||||
|
"./assets/images/priority-high.png",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
preloadLow: new URL(
|
||||||
|
/* webpackPreload: true */ /* webpackFetchPriority: "low" */
|
||||||
|
"./assets/styles/priority-low.css",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
prefetchAuto: new URL(
|
||||||
|
/* webpackPrefetch: true */ /* webpackFetchPriority: "auto" */
|
||||||
|
"./priority-auto.js",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
bothHints: new URL(
|
||||||
|
/* webpackPrefetch: true */ /* webpackPreload: true */ /* webpackFetchPriority: "high" */
|
||||||
|
"./assets/images/both-hints.png",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
noPriority: new URL(
|
||||||
|
/* webpackPrefetch: true */
|
||||||
|
"./assets/images/test.png",
|
||||||
|
import.meta.url
|
||||||
|
),
|
||||||
|
preloadFont: new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
"./assets/fonts/test.woff2",
|
||||||
|
import.meta.url
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefetchHighLink = document.head._children.find(
|
||||||
|
link => link.href.includes("priority-high.png") && link.rel === "prefetch"
|
||||||
|
);
|
||||||
|
expect(prefetchHighLink).toBeTruthy();
|
||||||
|
verifyLink(prefetchHighLink, {
|
||||||
|
rel: "prefetch",
|
||||||
|
as: "image",
|
||||||
|
fetchPriority: "high",
|
||||||
|
href: /priority-high\.png$/
|
||||||
|
});
|
||||||
|
|
||||||
|
const preloadLowLink = document.head._children.find(
|
||||||
|
link => link.href.includes("priority-low.css") && link.rel === "preload"
|
||||||
|
);
|
||||||
|
expect(preloadLowLink).toBeTruthy();
|
||||||
|
verifyLink(preloadLowLink, {
|
||||||
|
rel: "preload",
|
||||||
|
as: "style",
|
||||||
|
fetchPriority: "low",
|
||||||
|
href: /priority-low\.css$/
|
||||||
|
});
|
||||||
|
|
||||||
|
const prefetchAutoLink = document.head._children.find(
|
||||||
|
link => link.href.includes("priority-auto.js") && link.rel === "prefetch"
|
||||||
|
);
|
||||||
|
expect(prefetchAutoLink).toBeTruthy();
|
||||||
|
verifyLink(prefetchAutoLink, {
|
||||||
|
rel: "prefetch",
|
||||||
|
as: "script",
|
||||||
|
fetchPriority: "auto"
|
||||||
|
});
|
||||||
|
|
||||||
|
const bothHintsLink = document.head._children.find(
|
||||||
|
link => link.href.includes("both-hints.png")
|
||||||
|
);
|
||||||
|
expect(bothHintsLink).toBeTruthy();
|
||||||
|
expect(bothHintsLink.rel).toBe("preload");
|
||||||
|
expect(bothHintsLink._attributes.fetchpriority).toBe("high");
|
||||||
|
|
||||||
|
const noPriorityLink = document.head._children.find(
|
||||||
|
link => link.href.includes("test.png") && link.rel === "prefetch" &&
|
||||||
|
!link._attributes.fetchpriority
|
||||||
|
);
|
||||||
|
expect(noPriorityLink).toBeTruthy();
|
||||||
|
verifyLink(noPriorityLink, {
|
||||||
|
rel: "prefetch",
|
||||||
|
as: "image",
|
||||||
|
fetchPriority: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
const fontPreloadLink = document.head._children.find(
|
||||||
|
link => link.href.includes("test.woff2") && link.rel === "preload"
|
||||||
|
);
|
||||||
|
expect(fontPreloadLink).toBeTruthy();
|
||||||
|
verifyLink(fontPreloadLink, {
|
||||||
|
rel: "preload",
|
||||||
|
as: "font",
|
||||||
|
href: /test\.woff2$/
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should allow overriding as/type/media via magic comments", () => {
|
||||||
|
const override = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackPreloadAs: "font" */
|
||||||
|
/* webpackPreloadType: "font/woff2" */
|
||||||
|
/* webpackPreloadMedia: "(max-width: 600px)" */
|
||||||
|
"./assets/images/override.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
|
||||||
|
const link = document.head._children.find(
|
||||||
|
l => l.href.includes("override.png") && l.rel === "preload"
|
||||||
|
);
|
||||||
|
expect(link).toBeTruthy();
|
||||||
|
verifyLink(link, {
|
||||||
|
rel: "preload",
|
||||||
|
as: "font",
|
||||||
|
type: "font/woff2",
|
||||||
|
media: "(max-width: 600px)",
|
||||||
|
href: /override\.png$/
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should accept additional as tokens from Fetch Standard (e.g., sharedworker)", () => {
|
||||||
|
const u = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackPreloadAs: "sharedworker" */
|
||||||
|
"./priority-auto.js",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
|
||||||
|
const link = document.head._children.find(
|
||||||
|
l => l.href.includes("priority-auto.js") && l.rel === "preload"
|
||||||
|
);
|
||||||
|
expect(link).toBeTruthy();
|
||||||
|
verifyLink(link, {
|
||||||
|
rel: "preload",
|
||||||
|
as: "sharedworker",
|
||||||
|
href: /priority-auto\.js$/
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test asset file
|
||||||
|
console.log("priority-auto.js loaded");
|
|
@ -0,0 +1,66 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Mock document.head structure for testing
|
||||||
|
const mockCreateElement = (tagName) => {
|
||||||
|
const element = {
|
||||||
|
_type: tagName,
|
||||||
|
_attributes: {},
|
||||||
|
setAttribute(name, value) {
|
||||||
|
this._attributes[name] = value;
|
||||||
|
// Also set as property for fetchPriority
|
||||||
|
if (name === "fetchpriority") {
|
||||||
|
this.fetchPriority = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAttribute(name) {
|
||||||
|
return this._attributes[name];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set properties based on tag type
|
||||||
|
if (tagName === "link") {
|
||||||
|
element.rel = "";
|
||||||
|
element.as = "";
|
||||||
|
element.href = "";
|
||||||
|
element.type = undefined;
|
||||||
|
element.media = undefined;
|
||||||
|
element.fetchPriority = undefined;
|
||||||
|
} else if (tagName === "script") {
|
||||||
|
element.src = "";
|
||||||
|
element.async = true;
|
||||||
|
element.fetchPriority = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
beforeExecute: () => {
|
||||||
|
// Mock document for browser environment
|
||||||
|
global.document = {
|
||||||
|
head: {
|
||||||
|
_children: [],
|
||||||
|
appendChild(element) {
|
||||||
|
this._children.push(element);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
createElement: mockCreateElement
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock window for import.meta.url
|
||||||
|
global.window = {
|
||||||
|
location: {
|
||||||
|
href: "https://test.example.com/"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
findBundle() {
|
||||||
|
return ["main.js"];
|
||||||
|
},
|
||||||
|
|
||||||
|
moduleScope(scope) {
|
||||||
|
// Make document available in the module scope
|
||||||
|
scope.document = global.document;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Test JavaScript file
|
||||||
|
console.log("test.js loaded");
|
|
@ -0,0 +1,14 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
// Invalid fetchPriority value warning
|
||||||
|
[
|
||||||
|
/`webpackFetchPriority` expected "low", "high" or "auto", but received: invalid\./
|
||||||
|
],
|
||||||
|
// Invalid preloadAs (non-string)
|
||||||
|
[/`webpackPreloadAs` expected a string, but received: 123\./],
|
||||||
|
// Invalid preloadType (non-string)
|
||||||
|
[/`webpackPreloadType` expected a string, but received: 123\./],
|
||||||
|
// Invalid preloadMedia (non-string)
|
||||||
|
[/`webpackPreloadMedia` expected a string, but received: 456\./]
|
||||||
|
];
|
|
@ -0,0 +1,24 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** @type {import("../../../../types").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
mode: "development",
|
||||||
|
entry: {
|
||||||
|
main: "./index.js",
|
||||||
|
warnings: "./generate-warnings.js"
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "[name].js",
|
||||||
|
assetModuleFilename: "[name][ext]",
|
||||||
|
publicPath: "/public/"
|
||||||
|
},
|
||||||
|
target: "web",
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg|css|woff2)$/,
|
||||||
|
type: "asset/resource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
Binary file not shown.
After Width: | Height: | Size: 68 B |
|
@ -0,0 +1,49 @@
|
||||||
|
// Test cases for new URL() prefetch/preload support
|
||||||
|
|
||||||
|
it("should prefetch an image asset", () => {
|
||||||
|
const url = new URL(
|
||||||
|
/* webpackPrefetch: true */
|
||||||
|
"./prefetch-image.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
expect(url.href).toMatch(/prefetch-image\.png$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preload an image asset", () => {
|
||||||
|
const url = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
"./preload-image.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
expect(url.href).toMatch(/preload-image\.png$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preload with fetch priority", () => {
|
||||||
|
const url = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackFetchPriority: "high" */
|
||||||
|
"./priority-image.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
expect(url.href).toMatch(/priority-image\.png$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle invalid fetch priority", () => {
|
||||||
|
const url2 = new URL(
|
||||||
|
/* webpackPreload: true */
|
||||||
|
/* webpackFetchPriority: "invalid" */
|
||||||
|
"./invalid-priority-image.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
expect(url2.href).toMatch(/invalid-priority-image\.png$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle both prefetch and preload", () => {
|
||||||
|
const url3 = new URL(
|
||||||
|
/* webpackPrefetch: true */
|
||||||
|
/* webpackPreload: true */
|
||||||
|
"./both-hints-image.png",
|
||||||
|
import.meta.url
|
||||||
|
);
|
||||||
|
expect(url3.href).toMatch(/both-hints-image\.png$/);
|
||||||
|
});
|
Binary file not shown.
After Width: | Height: | Size: 68 B |
Binary file not shown.
After Width: | Height: | Size: 68 B |
Binary file not shown.
After Width: | Height: | Size: 68 B |
Binary file not shown.
After Width: | Height: | Size: 68 B |
|
@ -0,0 +1,7 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
findBundle() {
|
||||||
|
return ["main.js"];
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const supportsWorker = require("../../../helpers/supportsWorker");
|
||||||
|
|
||||||
|
module.exports = () => supportsWorker();
|
|
@ -0,0 +1,8 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
// Invalid fetch priority
|
||||||
|
[
|
||||||
|
/`webpackFetchPriority` expected "low", "high" or "auto", but received: invalid\./
|
||||||
|
]
|
||||||
|
];
|
|
@ -0,0 +1,18 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** @type {import("../../../../types").Configuration} */
|
||||||
|
module.exports = {
|
||||||
|
output: {
|
||||||
|
filename: "[name].js",
|
||||||
|
assetModuleFilename: "[name][ext]"
|
||||||
|
},
|
||||||
|
target: "web",
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.png$/,
|
||||||
|
type: "asset/resource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
|
@ -18448,8 +18448,10 @@ declare namespace exports {
|
||||||
export let moduleLoaded: "module.loaded";
|
export let moduleLoaded: "module.loaded";
|
||||||
export let nodeModuleDecorator: "__webpack_require__.nmd";
|
export let nodeModuleDecorator: "__webpack_require__.nmd";
|
||||||
export let onChunksLoaded: "__webpack_require__.O";
|
export let onChunksLoaded: "__webpack_require__.O";
|
||||||
|
export let prefetchAsset: "__webpack_require__.PA";
|
||||||
export let prefetchChunk: "__webpack_require__.E";
|
export let prefetchChunk: "__webpack_require__.E";
|
||||||
export let prefetchChunkHandlers: "__webpack_require__.F";
|
export let prefetchChunkHandlers: "__webpack_require__.F";
|
||||||
|
export let preloadAsset: "__webpack_require__.LA";
|
||||||
export let preloadChunk: "__webpack_require__.G";
|
export let preloadChunk: "__webpack_require__.G";
|
||||||
export let preloadChunkHandlers: "__webpack_require__.H";
|
export let preloadChunkHandlers: "__webpack_require__.H";
|
||||||
export let publicPath: "__webpack_require__.p";
|
export let publicPath: "__webpack_require__.p";
|
||||||
|
|
Loading…
Reference in New Issue