summaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/css/CssLoadingRuntimeModule.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/css/CssLoadingRuntimeModule.js')
-rw-r--r--node_modules/webpack/lib/css/CssLoadingRuntimeModule.js592
1 files changed, 592 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/css/CssLoadingRuntimeModule.js b/node_modules/webpack/lib/css/CssLoadingRuntimeModule.js
new file mode 100644
index 00000000..b3e677ca
--- /dev/null
+++ b/node_modules/webpack/lib/css/CssLoadingRuntimeModule.js
@@ -0,0 +1,592 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const { SyncWaterfallHook } = require("tapable");
+const Compilation = require("../Compilation");
+const RuntimeGlobals = require("../RuntimeGlobals");
+const RuntimeModule = require("../RuntimeModule");
+const Template = require("../Template");
+const compileBooleanMatcher = require("../util/compileBooleanMatcher");
+const { chunkHasCss } = require("./CssModulesPlugin");
+
+/** @typedef {import("../Chunk")} Chunk */
+/** @typedef {import("../ChunkGraph")} ChunkGraph */
+/** @typedef {import("../Compilation").RuntimeRequirementsContext} RuntimeRequirementsContext */
+/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
+
+/**
+ * @typedef {object} CssLoadingRuntimeModulePluginHooks
+ * @property {SyncWaterfallHook<[string, Chunk]>} createStylesheet
+ * @property {SyncWaterfallHook<[string, Chunk]>} linkPreload
+ * @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch
+ */
+
+/** @type {WeakMap<Compilation, CssLoadingRuntimeModulePluginHooks>} */
+const compilationHooksMap = new WeakMap();
+
+class CssLoadingRuntimeModule extends RuntimeModule {
+ /**
+ * @param {Compilation} compilation the compilation
+ * @returns {CssLoadingRuntimeModulePluginHooks} hooks
+ */
+ static getCompilationHooks(compilation) {
+ if (!(compilation instanceof Compilation)) {
+ throw new TypeError(
+ "The 'compilation' argument must be an instance of Compilation"
+ );
+ }
+ let hooks = compilationHooksMap.get(compilation);
+ if (hooks === undefined) {
+ hooks = {
+ createStylesheet: new SyncWaterfallHook(["source", "chunk"]),
+ linkPreload: new SyncWaterfallHook(["source", "chunk"]),
+ linkPrefetch: new SyncWaterfallHook(["source", "chunk"])
+ };
+ compilationHooksMap.set(compilation, hooks);
+ }
+ return hooks;
+ }
+
+ /**
+ * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
+ */
+ constructor(runtimeRequirements) {
+ super("css loading", 10);
+
+ this._runtimeRequirements = runtimeRequirements;
+ }
+
+ /**
+ * @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,
+ cssHeadDataCompression: withCompression
+ }
+ } = compilation;
+ const fn = RuntimeGlobals.ensureChunkHandlers;
+ const conditionMap = chunkGraph.getChunkConditionMap(
+ /** @type {Chunk} */ (chunk),
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @returns {boolean} true, if the chunk has css
+ */
+ (chunk, chunkGraph) =>
+ Boolean(chunkGraph.getChunkModulesIterableBySourceType(chunk, "css"))
+ );
+ const hasCssMatcher = compileBooleanMatcher(conditionMap);
+
+ const withLoading =
+ _runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
+ hasCssMatcher !== false;
+ const withPrefetch = this._runtimeRequirements.has(
+ RuntimeGlobals.prefetchChunkHandlers
+ );
+ const withPreload = this._runtimeRequirements.has(
+ RuntimeGlobals.preloadChunkHandlers
+ );
+ /** @type {boolean} */
+ const withHmr = _runtimeRequirements.has(
+ RuntimeGlobals.hmrDownloadUpdateHandlers
+ );
+ /** @type {Set<number | string | null>} */
+ const initialChunkIdsWithCss = new Set();
+ /** @type {Set<number | string | null>} */
+ const initialChunkIdsWithoutCss = new Set();
+ for (const c of /** @type {Chunk} */ (chunk).getAllInitialChunks()) {
+ (chunkHasCss(c, chunkGraph)
+ ? initialChunkIdsWithCss
+ : initialChunkIdsWithoutCss
+ ).add(c.id);
+ }
+
+ if (!withLoading && !withHmr && initialChunkIdsWithCss.size === 0) {
+ return null;
+ }
+
+ const { linkPreload, linkPrefetch } =
+ CssLoadingRuntimeModule.getCompilationHooks(compilation);
+
+ const withFetchPriority = _runtimeRequirements.has(
+ RuntimeGlobals.hasFetchPriority
+ );
+
+ const { createStylesheet } =
+ CssLoadingRuntimeModule.getCompilationHooks(compilation);
+
+ const stateExpression = withHmr
+ ? `${RuntimeGlobals.hmrRuntimeStatePrefix}_css`
+ : undefined;
+
+ const code = Template.asString([
+ "link = document.createElement('link');",
+ `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)};`
+ ),
+ "}"
+ ])
+ : ""
+ ]);
+
+ /** @type {(str: string) => number} */
+ const cc = str => str.charCodeAt(0);
+ const name = uniqueName
+ ? runtimeTemplate.concatenation(
+ "--webpack-",
+ { expr: "uniqueName" },
+ "-",
+ { expr: "chunkId" }
+ )
+ : runtimeTemplate.concatenation("--webpack-", { expr: "chunkId" });
+
+ return Template.asString([
+ "// object to store loaded and loading chunks",
+ "// undefined = chunk not loaded, null = chunk preloaded/prefetched",
+ "// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded",
+ `var installedChunks = ${
+ stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""
+ }{${Array.from(
+ initialChunkIdsWithoutCss,
+ id => `${JSON.stringify(id)}:0`
+ ).join(",")}};`,
+ "",
+ uniqueName
+ ? `var uniqueName = ${JSON.stringify(
+ runtimeTemplate.outputOptions.uniqueName
+ )};`
+ : "// data-webpack is not used as build has no uniqueName",
+ `var loadCssChunkData = ${runtimeTemplate.basicFunction(
+ "target, link, chunkId",
+ [
+ `var data, token = "", token2 = "", exports = {}, ${
+ withHmr ? "moduleIds = [], " : ""
+ }name = ${name}, i, cc = 1;`,
+ "try {",
+ Template.indent([
+ "if(!link) link = loadStylesheet(chunkId);",
+ // `link.sheet.rules` for legacy browsers
+ "var cssRules = link.sheet.cssRules || link.sheet.rules;",
+ "var j = cssRules.length - 1;",
+ "while(j > -1 && !data) {",
+ Template.indent([
+ "var style = cssRules[j--].style;",
+ "if(!style) continue;",
+ "data = style.getPropertyValue(name);"
+ ]),
+ "}"
+ ]),
+ "}catch(e){}",
+ "if(!data) {",
+ Template.indent([
+ "data = getComputedStyle(document.head).getPropertyValue(name);"
+ ]),
+ "}",
+ "if(!data) return [];",
+ withCompression
+ ? Template.asString([
+ // LZW decode
+ `var map = {}, char = data[0], oldPhrase = char, decoded = char, code = 256, maxCode = ${"\uFFFF".charCodeAt(
+ 0
+ )}, phrase;`,
+ "for (i = 1; i < data.length; i++) {",
+ Template.indent([
+ "cc = data[i].charCodeAt(0);",
+ "if (cc < 256) phrase = data[i]; else phrase = map[cc] ? map[cc] : (oldPhrase + char);",
+ "decoded += phrase;",
+ "char = phrase.charAt(0);",
+ "map[code] = oldPhrase + char;",
+ "if (++code > maxCode) { code = 256; map = {}; }",
+ "oldPhrase = phrase;"
+ ]),
+ "}",
+ "data = decoded;"
+ ])
+ : "// css head data compression is disabled",
+ "for(i = 0; cc; i++) {",
+ Template.indent([
+ "cc = data.charCodeAt(i);",
+ `if(cc == ${cc(":")}) { token2 = token; token = ""; }`,
+ `else if(cc == ${cc(
+ "/"
+ )}) { token = token.replace(/^_/, ""); token2 = token2.replace(/^_/, ""); exports[token2] = token; token = ""; token2 = ""; }`,
+ `else if(cc == ${cc("&")}) { ${
+ RuntimeGlobals.makeNamespaceObject
+ }(exports); }`,
+ `else if(!cc || cc == ${cc(
+ ","
+ )}) { token = token.replace(/^_/, ""); target[token] = (${runtimeTemplate.basicFunction(
+ "exports, module",
+ "module.exports = exports;"
+ )}).bind(null, exports); ${
+ withHmr ? "moduleIds.push(token); " : ""
+ }token = ""; token2 = ""; exports = {}; }`,
+ `else if(cc == ${cc("\\")}) { token += data[++i] }`,
+ "else { token += data[i]; }"
+ ]),
+ "}",
+ `${
+ withHmr ? `if(target == ${RuntimeGlobals.moduleFactories}) ` : ""
+ }installedChunks[chunkId] = 0;`,
+ withHmr ? "return moduleIds;" : ""
+ ]
+ )}`,
+ 'var loadingAttribute = "data-webpack-loading";',
+ `var loadStylesheet = ${runtimeTemplate.basicFunction(
+ `chunkId, url, done${withHmr ? ", hmr" : ""}${
+ withFetchPriority ? ", fetchPriority" : ""
+ }`,
+ [
+ 'var link, needAttach, key = "chunk-" + chunkId;',
+ withHmr ? "if(!hmr) {" : "",
+ 'var links = document.getElementsByTagName("link");',
+ "for(var i = 0; i < links.length; i++) {",
+ Template.indent([
+ "var 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))
+ ]),
+ "}",
+ `var 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);"
+ ])
+ )};`,
+ "if(link.getAttribute(loadingAttribute)) {",
+ Template.indent([
+ `var timeout = setTimeout(onLinkComplete.bind(null, undefined, { type: 'timeout', target: link }), ${loadTimeout});`,
+ "link.onerror = onLinkComplete.bind(null, link.onerror);",
+ "link.onload = onLinkComplete.bind(null, link.onload);"
+ ]),
+ "} else onLinkComplete(undefined, { type: 'load', target: link });", // We assume any existing stylesheet is render blocking
+ withHmr ? "hmr ? document.head.insertBefore(link, hmr) :" : "",
+ "needAttach && document.head.appendChild(link);",
+ "return link;"
+ ]
+ )};`,
+ initialChunkIdsWithCss.size > 2
+ ? `${JSON.stringify(
+ Array.from(initialChunkIdsWithCss)
+ )}.forEach(loadCssChunkData.bind(null, ${
+ RuntimeGlobals.moduleFactories
+ }, 0));`
+ : initialChunkIdsWithCss.size > 0
+ ? `${Array.from(
+ initialChunkIdsWithCss,
+ id =>
+ `loadCssChunkData(${
+ RuntimeGlobals.moduleFactories
+ }, 0, ${JSON.stringify(id)});`
+ ).join("")}`
+ : "// no initial css",
+ "",
+ withLoading
+ ? Template.asString([
+ `${fn}.css = ${runtimeTemplate.basicFunction(
+ `chunkId, promises${withFetchPriority ? " , fetchPriority" : ""}`,
+ [
+ "// css chunk loading",
+ `var 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",
+ `var promise = new Promise(${runtimeTemplate.expressionFunction(
+ "installedChunkData = installedChunks[chunkId] = [resolve, reject]",
+ "resolve, reject"
+ )});`,
+ "promises.push(installedChunkData[2] = promise);",
+ "",
+ "// start chunk loading",
+ `var url = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(chunkId);`,
+ "// create error before stack unwound to get useful stacktrace later",
+ "var error = new Error();",
+ `var 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([
+ "var errorType = event && event.type;",
+ "var 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;",
+ "installedChunkData[1](error);"
+ ]),
+ "} else {",
+ Template.indent([
+ `loadCssChunkData(${RuntimeGlobals.moduleFactories}, link, chunkId);`,
+ "installedChunkData[0]();"
+ ]),
+ "}"
+ ]),
+ "}"
+ ]),
+ "}"
+ ]
+ )};`,
+ `var link = loadStylesheet(chunkId, url, loadingEnded${
+ withFetchPriority ? ", fetchPriority" : ""
+ });`
+ ]),
+ "} 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;",
+ linkPrefetch.call(
+ Template.asString([
+ "var link = document.createElement('link');",
+ crossOriginLoading
+ ? `link.crossOrigin = ${JSON.stringify(
+ crossOriginLoading
+ )};`
+ : "",
+ `if (${RuntimeGlobals.scriptNonce}) {`,
+ Template.indent(
+ `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
+ ),
+ "}",
+ 'link.rel = "prefetch";',
+ 'link.as = "style";',
+ `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(chunkId);`
+ ]),
+ chunk
+ ),
+ "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;",
+ linkPreload.call(
+ Template.asString([
+ "var link = document.createElement('link');",
+ "link.charset = 'utf-8';",
+ `if (${RuntimeGlobals.scriptNonce}) {`,
+ Template.indent(
+ `link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
+ ),
+ "}",
+ 'link.rel = "preload";',
+ 'link.as = "style";',
+ `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.getChunkCssFilename}(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([
+ "var oldTags = [];",
+ "var newTags = [];",
+ `var applyHandler = ${runtimeTemplate.basicFunction("options", [
+ `return { dispose: ${runtimeTemplate.basicFunction(
+ "",
+ []
+ )}, apply: ${runtimeTemplate.basicFunction("", [
+ "var moduleIds = [];",
+ `newTags.forEach(${runtimeTemplate.expressionFunction(
+ "info[1].sheet.disabled = false",
+ "info"
+ )});`,
+ "while(oldTags.length) {",
+ Template.indent([
+ "var oldTag = oldTags.pop();",
+ "if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);"
+ ]),
+ "}",
+ "while(newTags.length) {",
+ Template.indent([
+ "var info = newTags.pop();",
+ `var chunkModuleIds = loadCssChunkData(${RuntimeGlobals.moduleFactories}, info[1], info[0]);`,
+ `chunkModuleIds.forEach(${runtimeTemplate.expressionFunction(
+ "moduleIds.push(id)",
+ "id"
+ )});`
+ ]),
+ "}",
+ "return moduleIds;"
+ ])} };`
+ ])}`,
+ `var 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",
+ [
+ "applyHandlers.push(applyHandler);",
+ `chunkIds.forEach(${runtimeTemplate.basicFunction("chunkId", [
+ `var filename = ${RuntimeGlobals.getChunkCssFilename}(chunkId);`,
+ `var url = ${RuntimeGlobals.publicPath} + filename;`,
+ "var oldTag = loadStylesheet(chunkId, url);",
+ "if(!oldTag) return;",
+ `promises.push(new Promise(${runtimeTemplate.basicFunction(
+ "resolve, reject",
+ [
+ `var link = loadStylesheet(chunkId, url + (url.indexOf("?") < 0 ? "?" : "&") + "hmr=" + Date.now(), ${runtimeTemplate.basicFunction(
+ "event",
+ [
+ 'if(event.type !== "load") {',
+ Template.indent([
+ "var errorType = event && event.type;",
+ "var 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;",
+ "reject(error);"
+ ]),
+ "} else {",
+ Template.indent([
+ "try { if(cssTextKey(oldTag) == cssTextKey(link)) { if(link.parentNode) link.parentNode.removeChild(link); return resolve(); } } catch(e) {}",
+ "var factories = {};",
+ "loadCssChunkData(factories, link, chunkId);",
+ `Object.keys(factories).forEach(${runtimeTemplate.expressionFunction(
+ "updatedModulesList.push(id)",
+ "id"
+ )})`,
+ "link.sheet.disabled = true;",
+ "oldTags.push(oldTag);",
+ "newTags.push([chunkId, link]);",
+ "resolve();"
+ ]),
+ "}"
+ ]
+ )}, oldTag);`
+ ]
+ )}));`
+ ])});`
+ ]
+ )}`
+ ])
+ : "// no hmr"
+ ]);
+ }
+}
+
+module.exports = CssLoadingRuntimeModule;