webpack
Version:
Packs ECMAScript/CommonJs/AMD modules for the browser. Allows you to split your codebase into multiple bundles, which can be loaded on demand. Supports loaders to preprocess files, i.e. json, jsx, es7, css, less, ... and your custom stuff.
746 lines (724 loc) • 27.9 kB
JavaScript
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
const { SyncWaterfallHook } = require("tapable");
/** @import Compilation from "../Compilation" */
const RuntimeGlobals = require("../runtime/RuntimeGlobals");
const RuntimeModule = require("../runtime/RuntimeModule");
const Template = require("../template/Template");
const compileBooleanMatcher = require("../util/compileBooleanMatcher");
const createHooksRegistry = require("../util/createHooksRegistry");
const { chunkHasCss } = require("./CssModulesPlugin");
/** @import Chunk, { ChunkId } from "../graph/Chunk" */
/** @import ChunkGraph from "../graph/ChunkGraph" */
/** @import { ReadOnlyRuntimeRequirements } from "../module/Module" */
const createCompilationHooks = () => ({
/**
* @type {SyncWaterfallHook<[string, Chunk]>}
* @since 5.66.0
*/
createStylesheet: new SyncWaterfallHook(["source", "chunk"]),
/**
* @type {SyncWaterfallHook<[string, Chunk]>}
* @since 5.91.0
*/
linkPreload: new SyncWaterfallHook(["source", "chunk"]),
/**
* @type {SyncWaterfallHook<[string, Chunk]>}
* @since 5.91.0
*/
linkPrefetch: new SyncWaterfallHook(["source", "chunk"]),
/**
* @type {SyncWaterfallHook<[string, Chunk]>}
* @since 5.107.0
*/
linkInsert: new SyncWaterfallHook(["source", "chunk"])
});
/**
* @typedef {ReturnType<typeof createCompilationHooks>} CssLoadingRuntimeModulePluginHooks
*/
class CssLoadingRuntimeModule extends RuntimeModule {
/**
* @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
*/
constructor(runtimeRequirements) {
super("css loading", 10);
/** @type {ReadOnlyRuntimeRequirements} */
this._runtimeRequirements = runtimeRequirements;
}
/**
* The initial chunks carrying a stylesheet, and the matcher for the ones the
* handler can still be asked to load.
* @private
* @returns {{ initialChunkIds: Set<ChunkId>, hasCssMatcher: ReturnType<typeof compileBooleanMatcher> }} loadable chunks
*/
_getLoadableChunks() {
const chunk = /** @type {Chunk} */ (this.chunk);
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const asyncChunks = chunk.getAllAsyncChunks();
/** @type {Set<ChunkId>} */
const initialChunkIds = new Set();
// A shared runtime can reach a stylesheet initially through one entry and
// asynchronously through another, where it still needs to be loaded.
for (const c of chunk.getAllInitialChunks()) {
if (chunkHasCss(c, chunkGraph) && !asyncChunks.has(c)) {
initialChunkIds.add(/** @type {ChunkId} */ (c.id));
}
}
// The predicate the stylesheet is emitted from: an `@import` external gives a
// chunk a css asset without a `CSS_TYPE` module, and it still has to load.
const conditionMap = chunkGraph.getChunkConditionMap(chunk, chunkHasCss);
// With no stylesheets left to request asynchronously, the handler is unused.
const loadableConditionMap = { ...conditionMap };
for (const id of initialChunkIds) {
loadableConditionMap[id] = false;
}
const hasCssMatcher =
compileBooleanMatcher(loadableConditionMap) === false
? false
: compileBooleanMatcher(conditionMap);
return { initialChunkIds, hasCssMatcher };
}
/**
* The `[handlerMap, key]` pairs this module installs onto a chunk handler map
* such as `__webpack_require__.f`, or `null` where it cannot name them.
* @returns {[string, string][] | null} installed chunk handlers (do not mutate)
*/
getInstalledChunkHandlers() {
const compilation = /** @type {Compilation} */ (this.compilation);
const chunk = /** @type {Chunk} */ (this.chunk);
const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
const runtimeRequirements = this._runtimeRequirements;
const withLoading =
runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
this._getLoadableChunks().hasCssMatcher !== false;
// Nothing at all is emitted without either, so nothing is installed either.
if (
!withLoading &&
!runtimeRequirements.has(RuntimeGlobals.hmrDownloadUpdateHandlers)
) {
return [];
}
const withHint =
compilation.outputOptions.environment.document ||
compilation.runtimeTemplate.isNeutralPlatform();
/** @type {[string, string][]} */
const handlers = [];
if (withLoading) handlers.push([RuntimeGlobals.ensureChunkHandlers, "css"]);
if (
withHint &&
runtimeRequirements.has(RuntimeGlobals.prefetchChunkHandlers) &&
chunk.hasChildByOrder(chunkGraph, "prefetch", true, chunkHasCss)
) {
handlers.push([RuntimeGlobals.prefetchChunkHandlers, "s"]);
}
if (
withHint &&
runtimeRequirements.has(RuntimeGlobals.preloadChunkHandlers) &&
(chunk.hasChildByOrder(chunkGraph, "preload", true, chunkHasCss) ||
chunk.hasChildByOrder(chunkGraph, "cssPreload", true, chunkHasCss))
) {
handlers.push([RuntimeGlobals.preloadChunkHandlers, "s"]);
}
return handlers;
}
/**
* Generates runtime code for this runtime module.
* @returns {string | null} runtime code
*/
generate() {
const { _runtimeRequirements } = this;
const compilation = /** @type {Compilation} */ (this.compilation);
const chunk = /** @type {Chunk} */ (this.chunk);
const {
chunkGraph,
runtimeTemplate,
outputOptions: {
crossOriginLoading,
uniqueName,
chunkLoadTimeout: loadTimeout,
charset,
resourceHints
}
} = compilation;
const dedupePrefetch = Boolean(resourceHints && resourceHints.dedupe);
const fn = RuntimeGlobals.ensureChunkHandlers;
const { initialChunkIds, hasCssMatcher } = this._getLoadableChunks();
const withLoading =
_runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
hasCssMatcher !== false;
/** @type {boolean} */
const withHmr = _runtimeRequirements.has(
RuntimeGlobals.hmrDownloadUpdateHandlers
);
if (!withLoading && !withHmr) {
return null;
}
const environment = compilation.outputOptions.environment;
const isNeutralPlatform = runtimeTemplate.isNeutralPlatform();
// only a node platform can read the stylesheet from disk; other document-less
// platforms (`target: "webworker"`) have no `fs`, so they keep the link code
const withoutDocument =
!environment.document && compilation.compiler.platform.node === true;
// Only a build that renders on a server meets a stylesheet it did not
// create, so every other build keeps the shorter adoption check.
const withServerRenderedLinks = this._runtimeRequirements.has(
RuntimeGlobals.hasServerRenderedStylesheets
);
const withPrefetch =
this._runtimeRequirements.has(RuntimeGlobals.prefetchChunkHandlers) &&
(environment.document || isNeutralPlatform) &&
chunk.hasChildByOrder(chunkGraph, "prefetch", true, chunkHasCss);
const withPreload =
this._runtimeRequirements.has(RuntimeGlobals.preloadChunkHandlers) &&
(environment.document || isNeutralPlatform) &&
(chunk.hasChildByOrder(chunkGraph, "preload", true, chunkHasCss) ||
// `parser.javascript.dynamicImportCssPreload` — CSS-only preload order.
chunk.hasChildByOrder(chunkGraph, "cssPreload", true, chunkHasCss));
// Under module output each stylesheet is a known file, so the urls are written
// out and read by id rather than built from the chunk id at runtime.
const cssUrls = runtimeTemplate.analyzableCssChunkUrls(
chunk,
chunkGraph,
_runtimeRequirements,
this
);
const { linkPreload, linkPrefetch, createStylesheet, linkInsert } =
CssLoadingRuntimeModule.getCompilationHooks(compilation);
const withFetchPriority = _runtimeRequirements.has(
RuntimeGlobals.hasFetchPriority
);
const stateExpression = withHmr
? `${RuntimeGlobals.hmrRuntimeStatePrefix}_css`
: undefined;
const code = Template.asString([
"link = document.createElement('link');",
charset ? "link.charset = 'utf-8';" : "",
`if (${RuntimeGlobals.scriptNonce}) {`,
Template.indent(
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
),
"}",
uniqueName
? 'link.setAttribute("data-webpack", uniqueName + ":" + key);'
: "",
withFetchPriority
? Template.asString([
"if(fetchPriority) {",
Template.indent(
'link.setAttribute("fetchpriority", fetchPriority);'
),
"}"
])
: "",
"link.setAttribute(loadingAttribute, 1);",
'link.rel = "stylesheet";',
"link.href = url;",
crossOriginLoading
? crossOriginLoading === "use-credentials"
? 'link.crossOrigin = "use-credentials";'
: Template.asString([
"if (link.href.indexOf(window.location.origin + '/') !== 0) {",
Template.indent(
`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
),
"}"
])
: ""
]);
const cst = runtimeTemplate.renderConst();
const lt = runtimeTemplate.renderLet();
// Whether an existing link still has rules on the way, and what its timeout
// then means: only a webpack-created link is an error, never an adopted one.
const adoptedLinkIsPending = withServerRenderedLinks
? 'fetching || (!link.sheet && link.href.indexOf(location.origin + "/") == 0)'
: "link.getAttribute(loadingAttribute)";
const timeoutEventType = withServerRenderedLinks
? "fetching ? 'timeout' : 'load'"
: "'timeout'";
// no DOM: read the emitted CSS via dynamic import('fs') (works on every node),
// collect it; never reject on a missing file
const readCssFromDisk =
withoutDocument || isNeutralPlatform
? `Promise.all([import('fs'), import('url')]).then(${runtimeTemplate.basicFunction(
"[{ readFile }, { URL }]",
[
`readFile(${runtimeTemplate.importMetaUrl("url")}, 'utf8', ${runtimeTemplate.basicFunction(
"err, content",
[
`if (!err) ${runtimeTemplate.cssServerStyleRegistry()}["chunk-" + chunkId] = content;`,
"loadingEnded({ type: 'load' });"
]
)});`
]
// No fs to import, or a url `readFile` rejects on sight (a CDN public
// path): nothing to collect, which is what a missing file already means.
)}).catch(${runtimeTemplate.expressionFunction(
"loadingEnded({ type: 'load' })"
)});`
: "";
const installedChunksObject = `{\n${Template.indent(
Array.from(initialChunkIds, (id) => `${JSON.stringify(id)}: 0`).join(
",\n"
)
)}\n}`;
// The url is read through a thunk so a runtime carrying many stylesheets builds
// only the one it loads.
/**
* @param {string} id expression naming the chunk whose stylesheet is wanted
* @returns {string} expression evaluating to its url
*/
const cssUrl = (id) =>
cssUrls === null
? `${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(${id})`
: `cssUrls[${id}]()`;
return Template.asString([
...(cssUrls
? [
`${cst} cssUrls = {\n${Template.indent(
Array.from(
cssUrls,
([id, url]) =>
`${JSON.stringify(String(id))}: ${runtimeTemplate.returningFunction(url)}`
).join(",\n")
)}\n};`
]
: []),
"// object to store loaded and loading chunks",
"// undefined = chunk not loaded, null = chunk preloaded/prefetched",
"// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded",
`${cst} installedChunks = ${
stateExpression
? runtimeTemplate.assignOr(stateExpression, installedChunksObject)
: installedChunksObject
};`,
"",
uniqueName
? `${cst} uniqueName = ${JSON.stringify(
runtimeTemplate.outputOptions.uniqueName
)};`
: "// data-webpack is not used as build has no uniqueName",
(withLoading && !withoutDocument) || withHmr
? Template.asString([
`${cst} loadingAttribute = "data-webpack-loading";`,
`${cst} loadStylesheet = ${runtimeTemplate.basicFunction(
`chunkId, url, done${
withFetchPriority ? ", fetchPriority" : ""
}${withHmr ? ", hmr" : ""}`,
[
`${lt} link, needAttach, key = "chunk-" + chunkId;`,
withHmr ? "if(!hmr) {" : "",
`${cst} links = document.getElementsByTagName("link");`,
"for(var i = 0; i < links.length; i++) {",
Template.indent([
`${cst} l = links[i];`,
`if(l.rel == "stylesheet" && (${
withHmr
? 'l.href.startsWith(url) || l.getAttribute("href").startsWith(url)'
: 'l.href == url || l.getAttribute("href") == url'
}${
uniqueName
? ' || l.getAttribute("data-webpack") == uniqueName + ":" + key'
: ""
})) { link = l; break; }`
]),
"}",
"if(!done) return link;",
withHmr ? "}" : "",
"if(!link) {",
Template.indent([
"needAttach = true;",
createStylesheet.call(code, /** @type {Chunk} */ (this.chunk))
]),
"}",
`${lt} timeout;`,
`${cst} onLinkComplete = ${runtimeTemplate.basicFunction(
"prev, event",
Template.asString([
"link.onerror = link.onload = null;",
"link.removeAttribute(loadingAttribute);",
"clearTimeout(timeout);",
'if(event && event.type != "load") link.parentNode.removeChild(link)',
"done(event);",
"if(prev) return prev(event);"
])
)};`,
...(withServerRenderedLinks
? [`${cst} fetching = link.getAttribute(loadingAttribute);`]
: []),
// An adopted stylesheet without a `sheet` has not applied yet, so a streamed
// server render no longer resolves before its rules are in.
`if(${adoptedLinkIsPending}) {`,
Template.indent([
// An adopted link that already failed replays no event, so its timeout
// resolves as a load: webpack did not create it and must not remove it.
`timeout = setTimeout(onLinkComplete.bind(null, undefined, { type: ${timeoutEventType}, target: link }), ${loadTimeout});`,
"link.onerror = onLinkComplete.bind(null, link.onerror);",
"link.onload = onLinkComplete.bind(null, link.onload);"
]),
"} else onLinkComplete(undefined, { type: 'load', target: link });", // a cross-origin sheet never exposes `sheet`, so it keeps the render-blocking assumption
withHmr && withFetchPriority
? 'if (hmr && hmr.getAttribute("fetchpriority")) link.setAttribute("fetchpriority", hmr.getAttribute("fetchpriority"));'
: "",
linkInsert.call(
withHmr
? Template.asString([
"if (hmr) {",
Template.indent(
"hmr.parentNode.insertBefore(link, hmr);"
),
"} else if (needAttach) {",
Template.indent("document.head.appendChild(link);"),
"}"
])
: Template.asString([
"if (needAttach) {",
Template.indent("document.head.appendChild(link);"),
"}"
]),
/** @type {Chunk} */ (this.chunk)
),
"return link;"
]
)};`
])
: "",
withLoading
? Template.asString([
`${fn}.css = ${runtimeTemplate.basicFunction(
`chunkId, promises${withFetchPriority ? " , fetchPriority" : ""}`,
[
"// css chunk loading",
`${lt} installedChunkData = ${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;`,
'if(installedChunkData !== 0) { // 0 means "already installed".',
Template.indent([
"",
'// a Promise means "currently loading".',
"if(installedChunkData) {",
Template.indent(["promises.push(installedChunkData[2]);"]),
"} else {",
Template.indent([
hasCssMatcher === true
? "if(true) { // all chunks have CSS"
: `if(${hasCssMatcher("chunkId")}) {`,
Template.indent([
"// setup Promise in chunk cache",
`${cst} promise = new Promise(${runtimeTemplate.expressionFunction(
"installedChunkData = installedChunks[chunkId] = [resolve, reject]",
"resolve, reject"
)});`,
"promises.push(installedChunkData[2] = promise);",
"",
"// start chunk loading",
`${cst} url = ${cssUrl("chunkId")};`,
"// create error before stack unwound to get useful stacktrace later",
`${cst} error = new Error();`,
`${cst} loadingEnded = ${runtimeTemplate.basicFunction(
"event",
[
`if(${RuntimeGlobals.hasOwnProperty}(installedChunks, chunkId)) {`,
Template.indent([
"installedChunkData = installedChunks[chunkId];",
"if(installedChunkData !== 0) installedChunks[chunkId] = undefined;",
"if(installedChunkData) {",
Template.indent([
'if(event.type !== "load") {',
Template.indent([
`${cst} errorType = event && event.type;`,
`${cst} realHref = event && event.target && event.target.href;`,
"error.message = 'Loading css chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realHref + ')';",
"error.name = 'ChunkLoadError';",
"error.type = errorType;",
"error.request = realHref;",
"error.event = event;",
"installedChunkData[1](error);"
]),
"} else {",
Template.indent([
"installedChunks[chunkId] = 0;",
"installedChunkData[0]();"
]),
"}"
]),
"}"
]),
"}"
]
)};`,
withoutDocument
? readCssFromDisk
: Template.asString([
isNeutralPlatform
? "if (typeof document !== 'undefined') {"
: "",
Template.indent([
`loadStylesheet(chunkId, url, loadingEnded${
withFetchPriority ? ", fetchPriority" : ""
});`
]),
isNeutralPlatform
? Template.asString([
"} else {",
Template.indent([readCssFromDisk]),
"}"
])
: ""
])
]),
"} else installedChunks[chunkId] = 0;"
]),
"}"
]),
"}"
]
)};`
])
: "// no chunk loading",
"",
withPrefetch && hasCssMatcher !== false
? `${
RuntimeGlobals.prefetchChunkHandlers
}.s = ${runtimeTemplate.basicFunction("chunkId", [
`if((!${
RuntimeGlobals.hasOwnProperty
}(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && ${
hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")
}) {`,
Template.indent([
"installedChunks[chunkId] = null;",
// prefetch is a browser-only resource hint; no-op without a DOM (e.g. node side of a universal build)
isNeutralPlatform
? "if (typeof document === 'undefined') return;"
: "",
linkPrefetch.call(
Template.asString([
`${cst} link = document.createElement('link');`,
charset ? "link.charset = 'utf-8';" : "",
crossOriginLoading
? `link.crossOrigin = ${JSON.stringify(
crossOriginLoading
)};`
: "",
`if (${RuntimeGlobals.scriptNonce}) {`,
Template.indent(
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
),
"}",
'link.rel = "prefetch";',
'link.as = "style";',
`link.href = ${cssUrl("chunkId")};`
]),
chunk
),
dedupePrefetch
? Template.asString([
// Chrome re-requests a resource when a prefetch link is added
// after it was already (pre)loaded via markup; skip in that case.
`${cst} links = document.getElementsByTagName("link");`,
`for(${lt} i = 0; i < links.length; i++) {`,
Template.indent([
`${cst} l = links[i];`,
'if(l.href === link.href && (l.rel === "prefetch" || l.rel === "preload")) return;'
]),
"}"
])
: "",
"document.head.appendChild(link);"
]),
"}"
])};`
: "// no prefetching",
"",
withPreload && hasCssMatcher !== false
? `${
RuntimeGlobals.preloadChunkHandlers
}.s = ${runtimeTemplate.basicFunction("chunkId", [
`if((!${
RuntimeGlobals.hasOwnProperty
}(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && ${
hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")
}) {`,
Template.indent([
"installedChunks[chunkId] = null;",
// preload is a browser-only resource hint; no-op without a DOM (e.g. node side of a universal build)
isNeutralPlatform
? "if (typeof document === 'undefined') return;"
: "",
linkPreload.call(
Template.asString([
`${cst} link = document.createElement('link');`,
charset ? "link.charset = 'utf-8';" : "",
`if (${RuntimeGlobals.scriptNonce}) {`,
Template.indent(
`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
),
"}",
'link.rel = "preload";',
'link.as = "style";',
`link.href = ${cssUrl("chunkId")};`,
crossOriginLoading
? crossOriginLoading === "use-credentials"
? 'link.crossOrigin = "use-credentials";'
: Template.asString([
"if (link.href.indexOf(window.location.origin + '/') !== 0) {",
Template.indent(
`link.crossOrigin = ${JSON.stringify(
crossOriginLoading
)};`
),
"}"
])
: ""
]),
chunk
),
"document.head.appendChild(link);"
]),
"}"
])};`
: "// no preloaded",
withHmr
? Template.asString([
`${cst} oldTags = [];`,
`${cst} newTags = [];`,
`${cst} applyHandler = ${runtimeTemplate.basicFunction("options", [
`return { ${runtimeTemplate.method("dispose", "", [
"while(oldTags.length) {",
Template.indent([
`${cst} oldTag = oldTags.pop();`,
`if(${runtimeTemplate.optionalChaining("oldTag", "parentNode")}) oldTag.parentNode.removeChild(oldTag);`
]),
"}"
])}, ${runtimeTemplate.method("apply", "", [
"while(newTags.length) {",
Template.indent([
`${cst} newTag = newTags.pop();`,
"newTag.sheet.disabled = false"
]),
"}"
])} };`
])}`,
`${cst} cssTextKey = ${runtimeTemplate.returningFunction(
`Array.from(link.sheet.cssRules, ${runtimeTemplate.returningFunction(
"r.cssText",
"r"
)}).join()`,
"link"
)};`,
`${
RuntimeGlobals.hmrDownloadUpdateHandlers
}.css = ${runtimeTemplate.basicFunction(
"chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList, css",
[
isNeutralPlatform || withoutDocument
? Template.asString([
"if (typeof document === 'undefined') {",
Template.indent([
// node SSR: refresh the server style registry from the re-emitted CSS instead of touching the DOM
`${cst} cssRemovedChunks = css && css.r;`,
`${cst} cssNames = css && css.n;`,
`${cst} registry = ${runtimeTemplate.cssServerStyleRegistry()};`,
`chunkIds.forEach(${runtimeTemplate.basicFunction(
"chunkId",
[
`${cst} key = "chunk-" + chunkId;`,
`if(${runtimeTemplate.optionalChaining(
"cssRemovedChunks",
"indexOf(chunkId)"
)} >= 0) { delete registry[key]; return; }`,
`${cst} url = ${RuntimeGlobals.publicPath} + (cssNames && cssNames[chunkId] || ${RuntimeGlobals.getChunkCssFilename}(chunkId));`,
`promises.push(Promise.all([import('fs'), import('url')]).then(${runtimeTemplate.basicFunction(
"[{ readFile }, { URL }]",
[
`return new Promise(${runtimeTemplate.basicFunction(
"resolve",
[
// best-effort: a non-file publicPath (e.g. a CDN) can't be read from disk, so skip
"try {",
Template.indent([
`readFile(${runtimeTemplate.importMetaUrl("url")}, 'utf8', ${runtimeTemplate.basicFunction(
"err, content",
[
"if (!err) registry[key] = content;",
"resolve();"
]
)});`
]),
"} catch (e) { resolve(); }"
]
)});`
]
)}));`
]
)});`,
"return;"
]),
"}"
])
: "",
"applyHandlers.push(applyHandler);",
"// Read CSS removed chunks from update manifest",
`${cst} cssRemovedChunks = css && css.r;`,
// The name map this runtime holds is refreshed by the update chunk, which
// has not run yet, so a name that moved is read off the manifest.
`${cst} cssNames = css && css.n;`,
`chunkIds.forEach(${runtimeTemplate.basicFunction("chunkId", [
`${cst} url = ${RuntimeGlobals.publicPath} + (cssNames && cssNames[chunkId] || ${RuntimeGlobals.getChunkCssFilename}(chunkId));`,
// The stylesheet in the document was loaded at the name this runtime
// still holds, so that is the name it is found by.
`${cst} oldTag = loadStylesheet(chunkId, ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(chunkId));`,
`if(!oldTag && !${withHmr} ) return;`,
"// Skip if CSS was removed",
`if(${runtimeTemplate.optionalChaining(
"cssRemovedChunks",
"indexOf(chunkId)"
)} >= 0) {`,
Template.indent(["oldTags.push(oldTag);", "return;"]),
"}",
"",
"// create error before stack unwound to get useful stacktrace later",
`${cst} error = new Error();`,
`promises.push(new Promise(${runtimeTemplate.basicFunction(
"resolve, reject",
[
`${cst} link = loadStylesheet(chunkId, url + (url.indexOf("?") < 0 ? "?" : "&") + "hmr=" + Date.now(), ${runtimeTemplate.basicFunction(
"event",
[
'if(event.type !== "load") {',
Template.indent([
`${cst} errorType = event && event.type;`,
`${cst} realHref = event && event.target && event.target.href;`,
"error.message = 'Loading css hot update chunk ' + chunkId + ' failed.\\n(' + errorType + ': ' + realHref + ')';",
"error.name = 'ChunkLoadError';",
"error.type = errorType;",
"error.request = realHref;",
"error.event = event;",
"reject(error);"
]),
"} else {",
Template.indent([
"try { if(cssTextKey(oldTag) == cssTextKey(link)) { if(link.parentNode) link.parentNode.removeChild(link); return resolve(); } } catch(e) {}",
"link.sheet.disabled = true;",
"oldTags.push(oldTag);",
"newTags.push(link);",
"resolve();"
]),
"}"
]
)}, ${withFetchPriority ? "undefined," : ""} oldTag);`
]
)}));`
])});`
]
)}`
])
: "// no hmr"
]);
}
}
CssLoadingRuntimeModule.getCompilationHooks = createHooksRegistry(
createCompilationHooks
);
module.exports = CssLoadingRuntimeModule;