diff --git a/src/index.js b/src/index.js
index 51809608..d2a19637 100644
--- a/src/index.js
+++ b/src/index.js
@@ -15,6 +15,7 @@ const {
compareModulesByIdentifier,
getUndoPath,
BASE_URI,
+ compileBooleanMatcher,
} = require("./utils");
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
@@ -105,6 +106,8 @@ const CODE_GENERATION_RESULT = {
/**
* @typedef {Object} MiniCssExtractPluginCompilationHooks
* @property {import("tapable").SyncWaterfallHook<[string, VarNames], string>} beforeTagInsert
+ * @property {SyncWaterfallHook<[string, Chunk]>} linkPreload
+ * @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch
*/
/**
@@ -526,7 +529,8 @@ class MiniCssExtractPlugin {
/**
* Returns all hooks for the given compilation
- * @param {Compilation} compilation
+ * @param {Compilation} compilation the compilation
+ * @returns {MiniCssExtractPluginCompilationHooks} hooks
*/
static getCompilationHooks(compilation) {
let hooks = compilationHooksMap.get(compilation);
@@ -537,6 +541,8 @@ class MiniCssExtractPlugin {
["source", "varNames"],
"string"
),
+ linkPreload: new SyncWaterfallHook(["source", "chunk"]),
+ linkPrefetch: new SyncWaterfallHook(["source", "chunk"]),
};
compilationHooksMap.set(compilation, hooks);
}
@@ -841,6 +847,20 @@ class MiniCssExtractPlugin {
return obj;
};
+ /**
+ * @param {Chunk} chunk chunk
+ * @param {ChunkGraph} chunkGraph chunk graph
+ * @returns {boolean} true, when the chunk has css
+ */
+ function chunkHasCss(chunk, chunkGraph) {
+ // this function replace:
+ // const chunkHasCss = require("webpack/lib/css/CssModulesPlugin").chunkHasCss;
+ return !!chunkGraph.getChunkModulesIterableBySourceType(
+ chunk,
+ "css/mini-extract"
+ );
+ }
+
class CssLoadingRuntimeModule extends RuntimeModule {
/**
* @param {Set} runtimeRequirements
@@ -854,7 +874,7 @@ class MiniCssExtractPlugin {
}
generate() {
- const { chunk, runtimeRequirements } = this;
+ const { chunkGraph, chunk, runtimeRequirements } = this;
const {
runtimeTemplate,
outputOptions: { crossOriginLoading },
@@ -863,7 +883,6 @@ class MiniCssExtractPlugin {
/** @type {Chunk} */ (chunk),
/** @type {Compilation} */ (this.compilation)
);
-
const withLoading =
runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
Object.keys(chunkMap).length > 0;
@@ -874,6 +893,20 @@ class MiniCssExtractPlugin {
if (!withLoading && !withHmr) {
return "";
}
+
+ const conditionMap = /** @type {ChunkGraph} */ (
+ chunkGraph
+ ).getChunkConditionMap(/** @type {Chunk} */ (chunk), chunkHasCss);
+ const hasCssMatcher = compileBooleanMatcher(conditionMap);
+ const withPrefetch = runtimeRequirements.has(
+ RuntimeGlobals.prefetchChunkHandlers
+ );
+ const withPreload = runtimeRequirements.has(
+ RuntimeGlobals.preloadChunkHandlers
+ );
+ const { linkPreload, linkPrefetch } =
+ MiniCssExtractPlugin.getCompilationHooks(compilation);
+
return Template.asString([
'if (typeof document === "undefined") return;',
`var createStylesheet = ${runtimeTemplate.basicFunction(
@@ -1088,6 +1121,87 @@ class MiniCssExtractPlugin {
)}`,
])
: "// no hmr",
+ "",
+ withPrefetch && hasCssMatcher !== false
+ ? `${
+ RuntimeGlobals.prefetchChunkHandlers
+ }.miniCss = ${runtimeTemplate.basicFunction("chunkId", [
+ `if((!${
+ RuntimeGlobals.hasOwnProperty
+ }(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && ${
+ hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")
+ }) {`,
+ Template.indent([
+ "installedCssChunks[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.require}.miniCssF(chunkId);`,
+ ]),
+ /** @type {Chunk} */ (chunk)
+ ),
+ "document.head.appendChild(link);",
+ ]),
+ "}",
+ ])};`
+ : "// no prefetching",
+ "",
+ withPreload && hasCssMatcher !== false
+ ? `${
+ RuntimeGlobals.preloadChunkHandlers
+ }.miniCss = ${runtimeTemplate.basicFunction("chunkId", [
+ `if((!${
+ RuntimeGlobals.hasOwnProperty
+ }(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && ${
+ hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")
+ }) {`,
+ Template.indent([
+ "installedCssChunks[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.require}.miniCssF(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
+ )};`
+ ),
+ "}",
+ ])
+ : "",
+ ]),
+ /** @type {Chunk} */ (chunk)
+ ),
+ "document.head.appendChild(link);",
+ ]),
+ "}",
+ ])};`
+ : "// no preloaded",
]);
}
}
@@ -1149,6 +1263,12 @@ class MiniCssExtractPlugin {
compilation.hooks.runtimeRequirementInTree
.for(RuntimeGlobals.hmrDownloadUpdateHandlers)
.tap(pluginName, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.prefetchChunkHandlers)
+ .tap(pluginName, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.preloadChunkHandlers)
+ .tap(pluginName, handler);
});
}
diff --git a/src/utils.js b/src/utils.js
index 68ab5f08..fc1c238f 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -214,6 +214,265 @@ function stringifyLocal(value) {
return typeof value === "function" ? value.toString() : JSON.stringify(value);
}
+/**
+ * @param {string} str string
+ * @returns {string} string
+ */
+const toSimpleString = (str) => {
+ if (`${+str}` === str) {
+ return str;
+ }
+ return JSON.stringify(str);
+};
+
+/**
+ * @param {string} str string
+ * @returns {string} quoted meta
+ */
+const quoteMeta = (str) => str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
+
+/**
+ * @param {Array} items items
+ * @returns {string} common prefix
+ */
+const getCommonPrefix = (items) => {
+ let prefix = items[0];
+
+ for (let i = 1; i < items.length; i++) {
+ const item = items[i];
+ for (let p = 0; p < prefix.length; p++) {
+ if (item[p] !== prefix[p]) {
+ prefix = prefix.slice(0, p);
+ break;
+ }
+ }
+ }
+
+ return prefix;
+};
+
+/**
+ * @param {Array} items items
+ * @returns {string} common suffix
+ */
+const getCommonSuffix = (items) => {
+ let suffix = items[0];
+
+ for (let i = 1; i < items.length; i++) {
+ const item = items[i];
+ for (let p = item.length - 1, s = suffix.length - 1; s >= 0; p--, s--) {
+ if (item[p] !== suffix[s]) {
+ suffix = suffix.slice(s + 1);
+ break;
+ }
+ }
+ }
+
+ return suffix;
+};
+
+/**
+ * @param {Set} itemsSet items set
+ * @param {(str: string) => string | false} getKey get key function
+ * @param {(str: Array) => boolean} condition condition
+ * @returns {Array>} list of common items
+ */
+const popCommonItems = (itemsSet, getKey, condition) => {
+ /** @type {Map>} */
+ const map = new Map();
+
+ for (const item of itemsSet) {
+ const key = getKey(item);
+ if (key) {
+ let list = map.get(key);
+ if (list === undefined) {
+ /** @type {Array} */
+ list = [];
+ map.set(key, list);
+ }
+ list.push(item);
+ }
+ }
+
+ /** @type {Array>} */
+ const result = [];
+
+ for (const list of map.values()) {
+ if (condition(list)) {
+ for (const item of list) {
+ itemsSet.delete(item);
+ }
+ result.push(list);
+ }
+ }
+
+ return result;
+};
+
+/**
+ * @param {Array} itemsArr array of items
+ * @returns {string} regexp
+ */
+const itemsToRegexp = (itemsArr) => {
+ if (itemsArr.length === 1) {
+ return quoteMeta(itemsArr[0]);
+ }
+
+ /** @type {Array} */
+ const finishedItems = [];
+
+ // merge single char items: (a|b|c|d|ef) => ([abcd]|ef)
+ let countOfSingleCharItems = 0;
+
+ for (const item of itemsArr) {
+ if (item.length === 1) {
+ // eslint-disable-next-line no-plusplus
+ countOfSingleCharItems++;
+ }
+ }
+
+ // special case for only single char items
+ if (countOfSingleCharItems === itemsArr.length) {
+ return `[${quoteMeta(itemsArr.sort().join(""))}]`;
+ }
+
+ const items = new Set(itemsArr.sort());
+
+ if (countOfSingleCharItems > 2) {
+ let singleCharItems = "";
+ for (const item of items) {
+ if (item.length === 1) {
+ singleCharItems += item;
+ items.delete(item);
+ }
+ }
+ finishedItems.push(`[${quoteMeta(singleCharItems)}]`);
+ }
+
+ // special case for 2 items with common prefix/suffix
+ if (finishedItems.length === 0 && items.size === 2) {
+ const prefix = getCommonPrefix(itemsArr);
+ const suffix = getCommonSuffix(
+ itemsArr.map((item) => item.slice(prefix.length))
+ );
+
+ if (prefix.length > 0 || suffix.length > 0) {
+ return `${quoteMeta(prefix)}${itemsToRegexp(
+ itemsArr.map((i) => i.slice(prefix.length, -suffix.length || undefined))
+ )}${quoteMeta(suffix)}`;
+ }
+ }
+
+ // special case for 2 items with common suffix
+ if (finishedItems.length === 0 && items.size === 2) {
+ /** @type {Iterator} */
+ const it = items[Symbol.iterator]();
+ const a = it.next().value;
+ const b = it.next().value;
+ if (a.length > 0 && b.length > 0 && a.slice(-1) === b.slice(-1)) {
+ return `${itemsToRegexp([a.slice(0, -1), b.slice(0, -1)])}${quoteMeta(
+ a.slice(-1)
+ )}`;
+ }
+ }
+
+ // find common prefix: (a1|a2|a3|a4|b5) => (a(1|2|3|4)|b5)
+ const prefixed = popCommonItems(
+ items,
+ (item) => (item.length >= 1 ? item[0] : false),
+ (list) => {
+ if (list.length >= 3) return true;
+ if (list.length <= 1) return false;
+ return list[0][1] === list[1][1];
+ }
+ );
+ for (const prefixedItems of prefixed) {
+ const prefix = getCommonPrefix(prefixedItems);
+ finishedItems.push(
+ `${quoteMeta(prefix)}${itemsToRegexp(
+ prefixedItems.map((i) => i.slice(prefix.length))
+ )}`
+ );
+ }
+
+ // find common suffix: (a1|b1|c1|d1|e2) => ((a|b|c|d)1|e2)
+ const suffixed = popCommonItems(
+ items,
+ (item) => (item.length >= 1 ? item.slice(-1) : false),
+ (list) => {
+ if (list.length >= 3) return true;
+ if (list.length <= 1) return false;
+ return list[0].slice(-2) === list[1].slice(-2);
+ }
+ );
+ for (const suffixedItems of suffixed) {
+ const suffix = getCommonSuffix(suffixedItems);
+ finishedItems.push(
+ `${itemsToRegexp(
+ suffixedItems.map((i) => i.slice(0, -suffix.length))
+ )}${quoteMeta(suffix)}`
+ );
+ }
+
+ // TODO further optimize regexp, i. e.
+ // use ranges: (1|2|3|4|a) => [1-4a]
+ const conditional = finishedItems.concat(Array.from(items, quoteMeta));
+ if (conditional.length === 1) return conditional[0];
+ return `(${conditional.join("|")})`;
+};
+
+/**
+ * @param {string[]} positiveItems positive items
+ * @param {string[]} negativeItems negative items
+ * @returns {function(string): string} a template function to determine the value at runtime
+ */
+const compileBooleanMatcherFromLists = (positiveItems, negativeItems) => {
+ if (positiveItems.length === 0) {
+ return () => "false";
+ }
+
+ if (negativeItems.length === 0) {
+ return () => "true";
+ }
+
+ if (positiveItems.length === 1) {
+ return (value) => `${toSimpleString(positiveItems[0])} == ${value}`;
+ }
+
+ if (negativeItems.length === 1) {
+ return (value) => `${toSimpleString(negativeItems[0])} != ${value}`;
+ }
+
+ const positiveRegexp = itemsToRegexp(positiveItems);
+ const negativeRegexp = itemsToRegexp(negativeItems);
+
+ if (positiveRegexp.length <= negativeRegexp.length) {
+ return (value) => `/^${positiveRegexp}$/.test(${value})`;
+ }
+
+ return (value) => `!/^${negativeRegexp}$/.test(${value})`;
+};
+
+// TODO simplify in the next major release and use it from webpack
+/**
+ * @param {Record} map value map
+ * @returns {boolean|(function(string): string)} true/false, when unconditionally true/false, or a template function to determine the value at runtime
+ */
+const compileBooleanMatcher = (map) => {
+ const positiveItems = Object.keys(map).filter((i) => map[i]);
+ const negativeItems = Object.keys(map).filter((i) => !map[i]);
+
+ if (positiveItems.length === 0) {
+ return false;
+ }
+
+ if (negativeItems.length === 0) {
+ return true;
+ }
+
+ return compileBooleanMatcherFromLists(positiveItems, negativeItems);
+};
+
module.exports = {
trueFn,
findModuleById,
@@ -227,4 +486,5 @@ module.exports = {
stringifyRequest,
stringifyLocal,
getUndoPath,
+ compileBooleanMatcher,
};
diff --git a/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/0.bb74e774207d1a909943.css b/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/0.ec6b19ad9e5afccf41ed.css
similarity index 100%
rename from test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/0.bb74e774207d1a909943.css
rename to test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/0.ec6b19ad9e5afccf41ed.css
diff --git a/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/bb74e774207d1a909943.css b/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/ec6b19ad9e5afccf41ed.css
similarity index 100%
rename from test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/bb74e774207d1a909943.css
rename to test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/ec6b19ad9e5afccf41ed.css
diff --git a/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/main.js b/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/main.js
index e288a56b..699df42d 100644
--- a/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/main.js
+++ b/test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/main.js
@@ -73,7 +73,7 @@ __webpack_require__.r(__webpack_exports__);
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
-/******/ __webpack_require__.h = () => ("bb74e774207d1a909943")
+/******/ __webpack_require__.h = () => ("ec6b19ad9e5afccf41ed")
/******/ })();
/******/
/******/ /* webpack/runtime/global */
@@ -253,6 +253,10 @@ __webpack_require__.r(__webpack_exports__);
/******/ };
/******/
/******/ // no hmr
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
diff --git a/test/cases/hmr/expected/main.js b/test/cases/hmr/expected/main.js
index 39fc3d64..ff182fd7 100644
--- a/test/cases/hmr/expected/main.js
+++ b/test/cases/hmr/expected/main.js
@@ -1029,6 +1029,10 @@ __webpack_require__.r(__webpack_exports__);
/******/ }));
/******/ });
/******/ }
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
diff --git a/test/cases/insert-function/expected/main.js b/test/cases/insert-function/expected/main.js
index 0f7f4ea5..bb3fbf19 100644
--- a/test/cases/insert-function/expected/main.js
+++ b/test/cases/insert-function/expected/main.js
@@ -238,6 +238,10 @@
/******/ };
/******/
/******/ // no hmr
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
diff --git a/test/cases/insert-string/expected/main.js b/test/cases/insert-string/expected/main.js
index faf5ef4c..d2550a28 100644
--- a/test/cases/insert-string/expected/main.js
+++ b/test/cases/insert-string/expected/main.js
@@ -234,6 +234,10 @@
/******/ };
/******/
/******/ // no hmr
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
diff --git a/test/cases/insert-undefined/expected/main.js b/test/cases/insert-undefined/expected/main.js
index eef6572b..ae8118ca 100644
--- a/test/cases/insert-undefined/expected/main.js
+++ b/test/cases/insert-undefined/expected/main.js
@@ -237,6 +237,10 @@
/******/ };
/******/
/******/ // no hmr
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
/******/ })();
/******/
/******/ /* webpack/runtime/jsonp chunk loading */
diff --git a/test/cases/prefetch-preload/a.css b/test/cases/prefetch-preload/a.css
new file mode 100644
index 00000000..5451a331
--- /dev/null
+++ b/test/cases/prefetch-preload/a.css
@@ -0,0 +1,3 @@
+.a {
+ color: red;
+}
diff --git a/test/cases/prefetch-preload/b.js b/test/cases/prefetch-preload/b.js
new file mode 100644
index 00000000..68eec89d
--- /dev/null
+++ b/test/cases/prefetch-preload/b.js
@@ -0,0 +1,3 @@
+import(/* webpackPrefetch: true, webpackChunkName: "b1" */ "./b1.css");
+import(/* webpackPreload: true, webpackChunkName: "b2" */ "./b2.css");
+import(/* webpackPrefetch: true, webpackChunkName: "b3" */ "./b3");
diff --git a/test/cases/prefetch-preload/b1.css b/test/cases/prefetch-preload/b1.css
new file mode 100644
index 00000000..effc583c
--- /dev/null
+++ b/test/cases/prefetch-preload/b1.css
@@ -0,0 +1,3 @@
+.b1 {
+ color: red;
+}
diff --git a/test/cases/prefetch-preload/b2.css b/test/cases/prefetch-preload/b2.css
new file mode 100644
index 00000000..e0331e1a
--- /dev/null
+++ b/test/cases/prefetch-preload/b2.css
@@ -0,0 +1,3 @@
+.b2 {
+ color: red;
+}
diff --git a/test/cases/prefetch-preload/b3.js b/test/cases/prefetch-preload/b3.js
new file mode 100644
index 00000000..e69de29b
diff --git a/test/cases/prefetch-preload/c.js b/test/cases/prefetch-preload/c.js
new file mode 100644
index 00000000..ce96cadc
--- /dev/null
+++ b/test/cases/prefetch-preload/c.js
@@ -0,0 +1,2 @@
+import(/* webpackPreload: true, webpackChunkName: "c1" */ "./c1.css");
+import(/* webpackPreload: true, webpackChunkName: "c2" */ "./c2.css");
diff --git a/test/cases/prefetch-preload/c1.css b/test/cases/prefetch-preload/c1.css
new file mode 100644
index 00000000..8725bcb0
--- /dev/null
+++ b/test/cases/prefetch-preload/c1.css
@@ -0,0 +1,3 @@
+.c1 {
+ color: red;
+}
diff --git a/test/cases/prefetch-preload/c2.css b/test/cases/prefetch-preload/c2.css
new file mode 100644
index 00000000..a124f6df
--- /dev/null
+++ b/test/cases/prefetch-preload/c2.css
@@ -0,0 +1,3 @@
+.c2 {
+ color: red;
+}
diff --git a/test/cases/prefetch-preload/expected/a.css b/test/cases/prefetch-preload/expected/a.css
new file mode 100644
index 00000000..98f445d8
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/a.css
@@ -0,0 +1,4 @@
+.a {
+ color: red;
+}
+
diff --git a/test/cases/prefetch-preload/expected/b.js b/test/cases/prefetch-preload/expected/b.js
new file mode 100644
index 00000000..7b97d9e9
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/b.js
@@ -0,0 +1,13 @@
+(self["webpackChunk"] = self["webpackChunk"] || []).push([[1],{
+
+/***/ 2:
+/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+
+__webpack_require__.e(/* import() | b1 */ 2).then(__webpack_require__.bind(__webpack_require__, 4));
+__webpack_require__.e(/* import() | b2 */ 3).then(__webpack_require__.bind(__webpack_require__, 5));
+__webpack_require__.e(/* import() | b3 */ 4).then(__webpack_require__.t.bind(__webpack_require__, 6, 23));
+
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/test/cases/prefetch-preload/expected/b1.css b/test/cases/prefetch-preload/expected/b1.css
new file mode 100644
index 00000000..4ba3041c
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/b1.css
@@ -0,0 +1,4 @@
+.b1 {
+ color: red;
+}
+
diff --git a/test/cases/prefetch-preload/expected/b2.css b/test/cases/prefetch-preload/expected/b2.css
new file mode 100644
index 00000000..3bc21aa1
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/b2.css
@@ -0,0 +1,4 @@
+.b2 {
+ color: red;
+}
+
diff --git a/test/cases/prefetch-preload/expected/c.js b/test/cases/prefetch-preload/expected/c.js
new file mode 100644
index 00000000..45d60ccc
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/c.js
@@ -0,0 +1,12 @@
+(self["webpackChunk"] = self["webpackChunk"] || []).push([[5],{
+
+/***/ 3:
+/***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
+
+__webpack_require__.e(/* import() | c1 */ 6).then(__webpack_require__.bind(__webpack_require__, 7));
+__webpack_require__.e(/* import() | c2 */ 7).then(__webpack_require__.bind(__webpack_require__, 8));
+
+
+/***/ })
+
+}]);
\ No newline at end of file
diff --git a/test/cases/prefetch-preload/expected/c1.css b/test/cases/prefetch-preload/expected/c1.css
new file mode 100644
index 00000000..b10e79dd
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/c1.css
@@ -0,0 +1,4 @@
+.c1 {
+ color: red;
+}
+
diff --git a/test/cases/prefetch-preload/expected/c2.css b/test/cases/prefetch-preload/expected/c2.css
new file mode 100644
index 00000000..a17ea975
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/c2.css
@@ -0,0 +1,4 @@
+.c2 {
+ color: red;
+}
+
diff --git a/test/cases/prefetch-preload/expected/main.js b/test/cases/prefetch-preload/expected/main.js
new file mode 100644
index 00000000..7fc8edd5
--- /dev/null
+++ b/test/cases/prefetch-preload/expected/main.js
@@ -0,0 +1,529 @@
+/******/ (() => { // webpackBootstrap
+/******/ var __webpack_modules__ = ({});
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var [chunkIds, fn, priority] = deferred[i];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/chunk prefetch function */
+/******/ (() => {
+/******/ __webpack_require__.F = {};
+/******/ __webpack_require__.E = (chunkId) => {
+/******/ Object.keys(__webpack_require__.F).map((key) => {
+/******/ __webpack_require__.F[key](chunkId);
+/******/ });
+/******/ }
+/******/ })();
+/******/
+/******/ /* webpack/runtime/chunk preload function */
+/******/ (() => {
+/******/ __webpack_require__.H = {};
+/******/ __webpack_require__.G = (chunkId) => {
+/******/ Object.keys(__webpack_require__.H).map((key) => {
+/******/ __webpack_require__.H[key](chunkId);
+/******/ });
+/******/ }
+/******/ })();
+/******/
+/******/ /* webpack/runtime/create fake namespace object */
+/******/ (() => {
+/******/ var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
+/******/ var leafPrototypes;
+/******/ // create a fake namespace object
+/******/ // mode & 1: value is a module id, require it
+/******/ // mode & 2: merge all properties of value into the ns
+/******/ // mode & 4: return value when already ns object
+/******/ // mode & 16: return value when it's Promise-like
+/******/ // mode & 8|1: behave like require
+/******/ __webpack_require__.t = function(value, mode) {
+/******/ if(mode & 1) value = this(value);
+/******/ if(mode & 8) return value;
+/******/ if(typeof value === 'object' && value) {
+/******/ if((mode & 4) && value.__esModule) return value;
+/******/ if((mode & 16) && typeof value.then === 'function') return value;
+/******/ }
+/******/ var ns = Object.create(null);
+/******/ __webpack_require__.r(ns);
+/******/ var def = {};
+/******/ leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];
+/******/ for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {
+/******/ Object.getOwnPropertyNames(current).forEach((key) => (def[key] = () => (value[key])));
+/******/ }
+/******/ def['default'] = () => (value);
+/******/ __webpack_require__.d(ns, def);
+/******/ return ns;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/ensure chunk */
+/******/ (() => {
+/******/ __webpack_require__.f = {};
+/******/ // This file contains only the entry chunk.
+/******/ // The chunk loading function for additional chunks
+/******/ __webpack_require__.e = (chunkId) => {
+/******/ return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {
+/******/ __webpack_require__.f[key](chunkId, promises);
+/******/ return promises;
+/******/ }, []));
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/get javascript chunk filename */
+/******/ (() => {
+/******/ // This function allow to reference async chunks
+/******/ __webpack_require__.u = (chunkId) => {
+/******/ // return url for filenames based on template
+/******/ return "" + {"0":"a","1":"b","2":"b1","3":"b2","4":"b3","5":"c","6":"c1","7":"c2"}[chunkId] + ".js";
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/get mini-css chunk filename */
+/******/ (() => {
+/******/ // This function allow to reference async chunks
+/******/ __webpack_require__.miniCssF = (chunkId) => {
+/******/ // return url for filenames based on template
+/******/ return "" + {"0":"a","2":"b1","3":"b2","6":"c1","7":"c2"}[chunkId] + ".css";
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/global */
+/******/ (() => {
+/******/ __webpack_require__.g = (function() {
+/******/ if (typeof globalThis === 'object') return globalThis;
+/******/ try {
+/******/ return this || new Function('return this')();
+/******/ } catch (e) {
+/******/ if (typeof window === 'object') return window;
+/******/ }
+/******/ })();
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/load script */
+/******/ (() => {
+/******/ var inProgress = {};
+/******/ // data-webpack is not used as build has no uniqueName
+/******/ // loadScript function to load a script via script tag
+/******/ __webpack_require__.l = (url, done, key, chunkId) => {
+/******/ if(inProgress[url]) { inProgress[url].push(done); return; }
+/******/ var script, needAttach;
+/******/ if(key !== undefined) {
+/******/ var scripts = document.getElementsByTagName("script");
+/******/ for(var i = 0; i < scripts.length; i++) {
+/******/ var s = scripts[i];
+/******/ if(s.getAttribute("src") == url) { script = s; break; }
+/******/ }
+/******/ }
+/******/ if(!script) {
+/******/ needAttach = true;
+/******/ script = document.createElement('script');
+/******/
+/******/ script.charset = 'utf-8';
+/******/ script.timeout = 120;
+/******/ if (__webpack_require__.nc) {
+/******/ script.setAttribute("nonce", __webpack_require__.nc);
+/******/ }
+/******/
+/******/
+/******/ script.src = url;
+/******/ }
+/******/ inProgress[url] = [done];
+/******/ var onScriptComplete = (prev, event) => {
+/******/ // avoid mem leaks in IE.
+/******/ script.onerror = script.onload = null;
+/******/ clearTimeout(timeout);
+/******/ var doneFns = inProgress[url];
+/******/ delete inProgress[url];
+/******/ script.parentNode && script.parentNode.removeChild(script);
+/******/ doneFns && doneFns.forEach((fn) => (fn(event)));
+/******/ if(prev) return prev(event);
+/******/ }
+/******/ var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), 120000);
+/******/ script.onerror = onScriptComplete.bind(null, script.onerror);
+/******/ script.onload = onScriptComplete.bind(null, script.onload);
+/******/ needAttach && document.head.appendChild(script);
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/publicPath */
+/******/ (() => {
+/******/ var scriptUrl;
+/******/ if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
+/******/ var document = __webpack_require__.g.document;
+/******/ if (!scriptUrl && document) {
+/******/ if (document.currentScript)
+/******/ scriptUrl = document.currentScript.src;
+/******/ if (!scriptUrl) {
+/******/ var scripts = document.getElementsByTagName("script");
+/******/ if(scripts.length) {
+/******/ var i = scripts.length - 1;
+/******/ while (i > -1 && (!scriptUrl || !/^http(s?):/.test(scriptUrl))) scriptUrl = scripts[i--].src;
+/******/ }
+/******/ }
+/******/ }
+/******/ // When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
+/******/ // or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
+/******/ if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
+/******/ scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
+/******/ __webpack_require__.p = scriptUrl;
+/******/ })();
+/******/
+/******/ /* webpack/runtime/css loading */
+/******/ (() => {
+/******/ if (typeof document === "undefined") return;
+/******/ var createStylesheet = (chunkId, fullhref, oldTag, resolve, reject) => {
+/******/ var linkTag = document.createElement("link");
+/******/
+/******/ linkTag.rel = "stylesheet";
+/******/ linkTag.type = "text/css";
+/******/ if (__webpack_require__.nc) {
+/******/ linkTag.nonce = __webpack_require__.nc;
+/******/ }
+/******/ var onLinkComplete = (event) => {
+/******/ // avoid mem leaks.
+/******/ linkTag.onerror = linkTag.onload = null;
+/******/ if (event.type === 'load') {
+/******/ resolve();
+/******/ } else {
+/******/ var errorType = event && event.type;
+/******/ var realHref = event && event.target && event.target.href || fullhref;
+/******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + errorType + ": " + realHref + ")");
+/******/ err.name = "ChunkLoadError";
+/******/ err.code = "CSS_CHUNK_LOAD_FAILED";
+/******/ err.type = errorType;
+/******/ err.request = realHref;
+/******/ if (linkTag.parentNode) linkTag.parentNode.removeChild(linkTag)
+/******/ reject(err);
+/******/ }
+/******/ }
+/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
+/******/ linkTag.href = fullhref;
+/******/
+/******/
+/******/ if (oldTag) {
+/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
+/******/ } else {
+/******/ document.head.appendChild(linkTag);
+/******/ }
+/******/ return linkTag;
+/******/ };
+/******/ var findStylesheet = (href, fullhref) => {
+/******/ var existingLinkTags = document.getElementsByTagName("link");
+/******/ for(var i = 0; i < existingLinkTags.length; i++) {
+/******/ var tag = existingLinkTags[i];
+/******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
+/******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return tag;
+/******/ }
+/******/ var existingStyleTags = document.getElementsByTagName("style");
+/******/ for(var i = 0; i < existingStyleTags.length; i++) {
+/******/ var tag = existingStyleTags[i];
+/******/ var dataHref = tag.getAttribute("data-href");
+/******/ if(dataHref === href || dataHref === fullhref) return tag;
+/******/ }
+/******/ };
+/******/ var loadStylesheet = (chunkId) => {
+/******/ return new Promise((resolve, reject) => {
+/******/ var href = __webpack_require__.miniCssF(chunkId);
+/******/ var fullhref = __webpack_require__.p + href;
+/******/ if(findStylesheet(href, fullhref)) return resolve();
+/******/ createStylesheet(chunkId, fullhref, null, resolve, reject);
+/******/ });
+/******/ }
+/******/ // object to store loaded CSS chunks
+/******/ var installedCssChunks = {
+/******/ 8: 0
+/******/ };
+/******/
+/******/ __webpack_require__.f.miniCss = (chunkId, promises) => {
+/******/ var cssChunks = {"0":1,"2":1,"3":1,"6":1,"7":1};
+/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
+/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
+/******/ promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(() => {
+/******/ installedCssChunks[chunkId] = 0;
+/******/ }, (e) => {
+/******/ delete installedCssChunks[chunkId];
+/******/ throw e;
+/******/ }));
+/******/ }
+/******/ };
+/******/
+/******/ // no hmr
+/******/
+/******/ __webpack_require__.F.miniCss = (chunkId) => {
+/******/ if((!__webpack_require__.o(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && !/^[1458]$/.test(chunkId)) {
+/******/ installedCssChunks[chunkId] = null;
+/******/ var link = document.createElement('link');
+/******/
+/******/ if (__webpack_require__.nc) {
+/******/ link.setAttribute("nonce", __webpack_require__.nc);
+/******/ }
+/******/ link.rel = "prefetch";
+/******/ link.as = "style";
+/******/ link.href = __webpack_require__.p + __webpack_require__.miniCssF(chunkId);
+/******/ document.head.appendChild(link);
+/******/ }
+/******/ };
+/******/
+/******/ __webpack_require__.H.miniCss = (chunkId) => {
+/******/ if((!__webpack_require__.o(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && !/^[1458]$/.test(chunkId)) {
+/******/ installedCssChunks[chunkId] = null;
+/******/ var link = document.createElement('link');
+/******/ link.charset = 'utf-8';
+/******/ if (__webpack_require__.nc) {
+/******/ link.setAttribute("nonce", __webpack_require__.nc);
+/******/ }
+/******/ link.rel = "preload";
+/******/ link.as = "style";
+/******/ link.href = __webpack_require__.p + __webpack_require__.miniCssF(chunkId);
+/******/ document.head.appendChild(link);
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // 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 = {
+/******/ 8: 0
+/******/ };
+/******/
+/******/ __webpack_require__.f.j = (chunkId, promises) => {
+/******/ // JSONP chunk loading for javascript
+/******/ var installedChunkData = __webpack_require__.o(installedChunks, chunkId) ? installedChunks[chunkId] : undefined;
+/******/ if(installedChunkData !== 0) { // 0 means "already installed".
+/******/
+/******/ // a Promise means "currently loading".
+/******/ if(installedChunkData) {
+/******/ promises.push(installedChunkData[2]);
+/******/ } else {
+/******/ if(true) { // all chunks have JS
+/******/ // setup Promise in chunk cache
+/******/ var promise = new Promise((resolve, reject) => (installedChunkData = installedChunks[chunkId] = [resolve, reject]));
+/******/ promises.push(installedChunkData[2] = promise);
+/******/
+/******/ // start chunk loading
+/******/ var url = __webpack_require__.p + __webpack_require__.u(chunkId);
+/******/ // create error before stack unwound to get useful stacktrace later
+/******/ var error = new Error();
+/******/ var loadingEnded = (event) => {
+/******/ if(__webpack_require__.o(installedChunks, chunkId)) {
+/******/ installedChunkData = installedChunks[chunkId];
+/******/ if(installedChunkData !== 0) installedChunks[chunkId] = undefined;
+/******/ if(installedChunkData) {
+/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
+/******/ var realSrc = event && event.target && event.target.src;
+/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
+/******/ error.name = 'ChunkLoadError';
+/******/ error.type = errorType;
+/******/ error.request = realSrc;
+/******/ installedChunkData[1](error);
+/******/ }
+/******/ }
+/******/ };
+/******/ __webpack_require__.l(url, loadingEnded, "chunk-" + chunkId, chunkId);
+/******/ }
+/******/ }
+/******/ }
+/******/ };
+/******/
+/******/ __webpack_require__.F.j = (chunkId) => {
+/******/ if((!__webpack_require__.o(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && true) {
+/******/ installedChunks[chunkId] = null;
+/******/ var link = document.createElement('link');
+/******/
+/******/ if (__webpack_require__.nc) {
+/******/ link.setAttribute("nonce", __webpack_require__.nc);
+/******/ }
+/******/ link.rel = "prefetch";
+/******/ link.as = "script";
+/******/ link.href = __webpack_require__.p + __webpack_require__.u(chunkId);
+/******/ document.head.appendChild(link);
+/******/ }
+/******/ };
+/******/
+/******/ __webpack_require__.H.j = (chunkId) => {
+/******/ if((!__webpack_require__.o(installedChunks, chunkId) || installedChunks[chunkId] === undefined) && true) {
+/******/ installedChunks[chunkId] = null;
+/******/ var link = document.createElement('link');
+/******/
+/******/ link.charset = 'utf-8';
+/******/ if (__webpack_require__.nc) {
+/******/ link.setAttribute("nonce", __webpack_require__.nc);
+/******/ }
+/******/ link.rel = "preload";
+/******/ link.as = "script";
+/******/ link.href = __webpack_require__.p + __webpack_require__.u(chunkId);
+/******/ document.head.appendChild(link);
+/******/ }
+/******/ };
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var [chunkIds, moreModules, runtime] = data;
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/******/ /* webpack/runtime/chunk prefetch trigger */
+/******/ (() => {
+/******/ var chunkToChildrenMap = {
+/******/ "1": [
+/******/ 2,
+/******/ 4
+/******/ ]
+/******/ };
+/******/ __webpack_require__.f.prefetch = (chunkId, promises) => (Promise.all(promises).then(() => {
+/******/ var chunks = chunkToChildrenMap[chunkId];
+/******/ Array.isArray(chunks) && chunks.map(__webpack_require__.E);
+/******/ }));
+/******/ })();
+/******/
+/******/ /* webpack/runtime/chunk preload trigger */
+/******/ (() => {
+/******/ var chunkToChildrenMap = {
+/******/ "1": [
+/******/ 3
+/******/ ],
+/******/ "5": [
+/******/ 6,
+/******/ 7
+/******/ ]
+/******/ };
+/******/ __webpack_require__.f.preload = (chunkId) => {
+/******/ var chunks = chunkToChildrenMap[chunkId];
+/******/ Array.isArray(chunks) && chunks.map(__webpack_require__.G);
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/startup prefetch */
+/******/ (() => {
+/******/ __webpack_require__.O(0, [8], () => {
+/******/ [0,1,5].map(__webpack_require__.E);
+/******/ }, 5);
+/******/ })();
+/******/
+/************************************************************************/
+var __webpack_exports__ = {};
+__webpack_require__.e(/* import() | a */ 0).then(__webpack_require__.bind(__webpack_require__, 1));
+__webpack_require__.e(/* import() | b */ 1).then(__webpack_require__.t.bind(__webpack_require__, 2, 23));
+__webpack_require__.e(/* import() | c */ 5).then(__webpack_require__.t.bind(__webpack_require__, 3, 23));
+
+__webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/ })()
+;
\ No newline at end of file
diff --git a/test/cases/prefetch-preload/index.js b/test/cases/prefetch-preload/index.js
new file mode 100644
index 00000000..e1c87500
--- /dev/null
+++ b/test/cases/prefetch-preload/index.js
@@ -0,0 +1,3 @@
+import(/* webpackPrefetch: true, webpackChunkName: "a" */ "./a.css");
+import(/* webpackPrefetch: true, webpackChunkName: "b" */ "./b");
+import(/* webpackPrefetch: true, webpackChunkName: "c" */ "./c");
diff --git a/test/cases/prefetch-preload/webpack.config.js b/test/cases/prefetch-preload/webpack.config.js
new file mode 100644
index 00000000..cf55c08c
--- /dev/null
+++ b/test/cases/prefetch-preload/webpack.config.js
@@ -0,0 +1,18 @@
+import Self from "../../../src";
+
+module.exports = {
+ entry: "./index.js",
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: [Self.loader, "css-loader"],
+ },
+ ],
+ },
+ plugins: [
+ new Self({
+ filename: "[name].css",
+ }),
+ ],
+};
diff --git a/test/manual/index.html b/test/manual/index.html
index 3b7d2ca4..8c93cb71 100644
--- a/test/manual/index.html
+++ b/test/manual/index.html
@@ -23,6 +23,16 @@
background: lightgreen;
}
+
+
@@ -97,6 +107,20 @@
+
+
Prefetch CSS: Must be blue and green after click.
+
+ to load
+ prefetched chunk
+
+
+
+
Preload CSS: Must be white, then blue, then green after click.
+
+ to load
+ preloaded chunk
+
+