diff --git a/src/index.js b/src/index.js
index fe1b2f92..6d711ad7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -323,10 +323,13 @@ class ExtractCssChunksPlugin {
}
);
const { insert } = this.options;
+ const supportsPreload =
+ '(function() { try { return document.createElement("link").relList.supports("preload"); } catch(e) { return false; }}());';
return Template.asString([
source,
'',
`// ${pluginName} CSS loading`,
+ `var supportsPreload = ${supportsPreload}`,
`var cssChunks = ${JSON.stringify(chunkMap)};`,
'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);',
'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {',
@@ -340,8 +343,7 @@ class ExtractCssChunksPlugin {
Template.indent([
'var tag = existingLinkTags[i];',
'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");',
- 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();',
- ]),
+ 'if((tag.rel === "stylesheet" || tag.rel === "preload") && (dataHref === href || dataHref === fullhref)) return resolve();', ]),
'}',
'var existingStyleTags = document.getElementsByTagName("style");',
'for(var i = 0; i < existingStyleTags.length; i++) {',
@@ -352,8 +354,8 @@ class ExtractCssChunksPlugin {
]),
'}',
'var linkTag = document.createElement("link");',
- 'linkTag.rel = "stylesheet";',
- 'linkTag.type = "text/css";',
+ 'linkTag.rel = supportsPreload ? "preload": "stylesheet";',
+ 'supportsPreload ? linkTag.as = "style" : linkTag.type = "text/css";',
'linkTag.onload = resolve;',
'linkTag.onerror = function(event) {',
Template.indent([
@@ -383,7 +385,18 @@ class ExtractCssChunksPlugin {
: 'var head = document.getElementsByTagName("head")[0]; head.appendChild(linkTag)',
]),
'}).then(function() {',
- Template.indent(['installedCssChunks[chunkId] = 0;']),
+ Template.indent([
+ 'installedCssChunks[chunkId] = 0;',
+ 'if(supportsPreload) {',
+ Template.indent([
+ 'var execLinkTag = document.createElement("link");',
+ `execLinkTag.href = ${mainTemplate.requireFn}.p + ${linkHrefPath};`,
+ 'execLinkTag.rel = "stylesheet";',
+ 'execLinkTag.type = "text/css";',
+ 'document.body.appendChild(execLinkTag);',
+ ]),
+ '}',
+ ]),
'}));',
]),
'}',
diff --git a/test/HMR.test.js b/test/HMR.test.js
index 2a597ddc..39947d77 100644
--- a/test/HMR.test.js
+++ b/test/HMR.test.js
@@ -30,7 +30,8 @@ describe('HMR', () => {
jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);
- document.head.innerHTML = '';
+ document.head.innerHTML =
+ '';
document.body.innerHTML = '';
});
diff --git a/test/__snapshots__/HMR.test.js.snap b/test/__snapshots__/HMR.test.js.snap
index 269260d0..7d1f41a1 100644
--- a/test/__snapshots__/HMR.test.js.snap
+++ b/test/__snapshots__/HMR.test.js.snap
@@ -2,7 +2,7 @@
exports[`HMR should handle error event 1`] = `"[HMR] css reload %s"`;
-exports[`HMR should handle error event 2`] = `""`;
+exports[`HMR should handle error event 2`] = `""`;
exports[`HMR should reloads with # link href 1`] = `"[HMR] css reload %s"`;
@@ -18,7 +18,7 @@ exports[`HMR should reloads with link without href 2`] = `""`;
+exports[`HMR should reloads with locals 2`] = `""`;
exports[`HMR should reloads with non http/https link href 1`] = `"[HMR] css reload %s"`;
@@ -26,14 +26,14 @@ exports[`HMR should reloads with non http/https link href 2`] = `""`;
+exports[`HMR should reloads with reloadAll option 2`] = `""`;
exports[`HMR should works 1`] = `"[HMR] css reload %s"`;
-exports[`HMR should works 2`] = `""`;
+exports[`HMR should works 2`] = `""`;
exports[`HMR should works with multiple updates 1`] = `"[HMR] css reload %s"`;
-exports[`HMR should works with multiple updates 2`] = `""`;
+exports[`HMR should works with multiple updates 2`] = `""`;
-exports[`HMR should works with multiple updates 3`] = `""`;
+exports[`HMR should works with multiple updates 3`] = `""`;
diff --git a/test/cases/insert-function/expected/main.js b/test/cases/insert-function/expected/main.js
index 507701ba..7c4ef54a 100644
--- a/test/cases/insert-function/expected/main.js
+++ b/test/cases/insert-function/expected/main.js
@@ -82,6 +82,7 @@
/******/
/******/
/******/ // extract-css-chunks-webpack-plugin CSS loading
+/******/ var supportsPreload = (function() { try { return document.createElement("link").relList.supports("preload"); } catch(e) { return false; }}());
/******/ var cssChunks = {"1":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
@@ -92,7 +93,7 @@
/******/ 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 resolve();
+/******/ if((tag.rel === "stylesheet" || tag.rel === "preload") && (dataHref === href || dataHref === fullhref)) return resolve();
/******/ }
/******/ var existingStyleTags = document.getElementsByTagName("style");
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
@@ -101,8 +102,8 @@
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
/******/ }
/******/ var linkTag = document.createElement("link");
-/******/ linkTag.rel = "stylesheet";
-/******/ linkTag.type = "text/css";
+/******/ linkTag.rel = supportsPreload ? "preload": "stylesheet";
+/******/ supportsPreload ? linkTag.as = "style" : linkTag.type = "text/css";
/******/ linkTag.onload = resolve;
/******/ linkTag.onerror = function(event) {
/******/ var request = event && event.target && event.target.src || fullhref;
@@ -122,16 +123,16 @@
/******/ reference.parentNode.insertBefore(linkTag, reference);
/******/ }
/******/ };
-/******/ if (typeof insert === 'function') { insert(linkTag); }
-/******/ else { var target = document.querySelector(function insert(linkTag) {
-/******/ const reference = document.querySelector('.hot-reload');
-/******/
-/******/ if (reference) {
-/******/ reference.parentNode.insertBefore(linkTag, reference);
-/******/ }
-/******/ }); target && insert === 'body' ? target && target.insertBefore(linkTag,target.firstChild) : target.appendChild(linkTag); }
+/******/ insert(linkTag);
/******/ }).then(function() {
/******/ installedCssChunks[chunkId] = 0;
+/******/ if(supportsPreload) {
+/******/ var execLinkTag = document.createElement("link");
+/******/ execLinkTag.href = __webpack_require__.p + "" + chunkId + ".css";
+/******/ execLinkTag.rel = "stylesheet";
+/******/ execLinkTag.type = "text/css";
+/******/ document.body.appendChild(execLinkTag);
+/******/ }
/******/ }));
/******/ }
/******/
diff --git a/test/cases/insert-function/webpack.config.e2e.js b/test/cases/insert-function/webpack.config.e2e.js
index f35a1c97..636f8479 100644
--- a/test/cases/insert-function/webpack.config.e2e.js
+++ b/test/cases/insert-function/webpack.config.e2e.js
@@ -64,7 +64,9 @@ module.exports = {
new Self({
filename: '[name].css',
chunkFilename: '[id].css',
- insert: 'body',
+ insert: (linkTag) => {
+ document.head.appendChild(linkTag)
+ },
}),
],
devServer: {
diff --git a/test/cases/insert-string/expected/main.js b/test/cases/insert-string/expected/main.js
index 78886571..003729a2 100644
--- a/test/cases/insert-string/expected/main.js
+++ b/test/cases/insert-string/expected/main.js
@@ -82,6 +82,7 @@
/******/
/******/
/******/ // extract-css-chunks-webpack-plugin CSS loading
+/******/ var supportsPreload = (function() { try { return document.createElement("link").relList.supports("preload"); } catch(e) { return false; }}());
/******/ var cssChunks = {"1":1};
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
@@ -92,7 +93,7 @@
/******/ 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 resolve();
+/******/ if((tag.rel === "stylesheet" || tag.rel === "preload") && (dataHref === href || dataHref === fullhref)) return resolve();
/******/ }
/******/ var existingStyleTags = document.getElementsByTagName("style");
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
@@ -101,8 +102,8 @@
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
/******/ }
/******/ var linkTag = document.createElement("link");
-/******/ linkTag.rel = "stylesheet";
-/******/ linkTag.type = "text/css";
+/******/ linkTag.rel = supportsPreload ? "preload": "stylesheet";
+/******/ supportsPreload ? linkTag.as = "style" : linkTag.type = "text/css";
/******/ linkTag.onload = resolve;
/******/ linkTag.onerror = function(event) {
/******/ var request = event && event.target && event.target.src || fullhref;
@@ -115,11 +116,17 @@
/******/ };
/******/ linkTag.href = fullhref;
/******/
-/******/ var insert = "body";
-/******/ if (typeof insert === 'function') { insert(linkTag); }
-/******/ else { var target = document.querySelector("body"); target && insert === 'body' ? target && target.insertBefore(linkTag,target.firstChild) : target.appendChild(linkTag); }
+/******/ var insert = body;
+/******/ insert(linkTag);
/******/ }).then(function() {
/******/ installedCssChunks[chunkId] = 0;
+/******/ if(supportsPreload) {
+/******/ var execLinkTag = document.createElement("link");
+/******/ execLinkTag.href = __webpack_require__.p + "" + chunkId + ".css";
+/******/ execLinkTag.rel = "stylesheet";
+/******/ execLinkTag.type = "text/css";
+/******/ document.body.appendChild(execLinkTag);
+/******/ }
/******/ }));
/******/ }
/******/
diff --git a/test/cases/insert-string/webpack.config.e2e.js b/test/cases/insert-string/webpack.config.e2e.js
index c18b3591..504c5bf1 100644
--- a/test/cases/insert-string/webpack.config.e2e.js
+++ b/test/cases/insert-string/webpack.config.e2e.js
@@ -64,7 +64,7 @@ module.exports = {
new Self({
filename: '[name].css',
chunkFilename: '[id].css',
- insert: 'body',
+ insert: '(linkTag) => { document.head.appendChild(linkTag) }',
}),
],
devServer: {
diff --git a/test/cases/publicpath-emptystring/expected/main.css b/test/cases/publicpath-emptystring/expected/main.css
index b6282c08..339ed982 100644
--- a/test/cases/publicpath-emptystring/expected/main.css
+++ b/test/cases/publicpath-emptystring/expected/main.css
@@ -1,5 +1,5 @@
body {
background: red;
- background-image: url(cd0bb358c45b584743d8ce4991777c42.svg);
+ background-image: url(c9e192c015437a21dea1faa1d30f4941.svg);
}
diff --git a/test/cases/publicpath-function/expected/nested/again/style.css b/test/cases/publicpath-function/expected/nested/again/style.css
index 3e223c60..c2846f3d 100644
--- a/test/cases/publicpath-function/expected/nested/again/style.css
+++ b/test/cases/publicpath-function/expected/nested/again/style.css
@@ -1,5 +1,5 @@
body {
background: green;
- background-image: url(../../cd0bb358c45b584743d8ce4991777c42.svg);
+ background-image: url(../../c9e192c015437a21dea1faa1d30f4941.svg);
}
diff --git a/test/cases/publicpath-function/expected/nested/style.css b/test/cases/publicpath-function/expected/nested/style.css
index 147ac268..a6f3d9ec 100644
--- a/test/cases/publicpath-function/expected/nested/style.css
+++ b/test/cases/publicpath-function/expected/nested/style.css
@@ -1,5 +1,5 @@
body {
background: red;
- background-image: url(../cd0bb358c45b584743d8ce4991777c42.svg);
+ background-image: url(../c9e192c015437a21dea1faa1d30f4941.svg);
}
diff --git a/test/cases/publicpath-trailing-slash/expected/main.css b/test/cases/publicpath-trailing-slash/expected/main.css
index 0e1e2d07..6d14c42a 100644
--- a/test/cases/publicpath-trailing-slash/expected/main.css
+++ b/test/cases/publicpath-trailing-slash/expected/main.css
@@ -1,5 +1,5 @@
body {
background: red;
- background-image: url(/static/img/cd0bb358c45b584743d8ce4991777c42.svg);
+ background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
}
diff --git a/test/cases/simple-publicpath/expected/main.css b/test/cases/simple-publicpath/expected/main.css
index 0e1e2d07..6d14c42a 100644
--- a/test/cases/simple-publicpath/expected/main.css
+++ b/test/cases/simple-publicpath/expected/main.css
@@ -1,5 +1,5 @@
body {
background: red;
- background-image: url(/static/img/cd0bb358c45b584743d8ce4991777c42.svg);
+ background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
}
diff --git a/test/cases/split-chunks/index.js b/test/cases/split-chunks/index.js
index b90fdc81..83d40d8e 100644
--- a/test/cases/split-chunks/index.js
+++ b/test/cases/split-chunks/index.js
@@ -1,3 +1,3 @@
-// eslint-disable-next-line import/no-extraneous-dependencies
+// eslint-disable-next-line
import 'bootstrap.css';
import './style.css';
diff --git a/test/inject-option.test.js b/test/inject-option.test.js
index ac8bf1ac..e66dfe45 100644
--- a/test/inject-option.test.js
+++ b/test/inject-option.test.js
@@ -13,14 +13,14 @@ describe('insert-options', () => {
});
await page.goto('http://localhost:5000/');
});
- it('stylesheet was injected into body', async () => {
- await page.waitFor(3000);
- const bodyHTML = await page.evaluate(() => document.body.innerHTML);
-
- await expect(bodyHTML.indexOf('type="text/css"') > 0).toBe(true);
+ it('style preload was injected into body', async () => {
+ // preloaded1 + main + inject
+ await expect(await page.$$eval('[type="text/css"]', links => links.length)).toEqual(3);
+ // inject
+ await expect(await page.$$eval('[rel="preload"]', preloads => preloads.length)).toEqual(1);
});
- it('body background style set correctly', async () => {
+ it('body background style was not set', async () => {
const bodyStyle = await page.evaluate(() =>
getComputedStyle(document.body).getPropertyValue('background-color')
);
@@ -38,13 +38,14 @@ describe('insert-options', () => {
});
await page.goto('http://localhost:3001/');
});
- it('stylesheet was injected into body', async () => {
- const bodyHTML = await page.evaluate(() => document.body.innerHTML);
-
- await expect(bodyHTML.indexOf('type="text/css"') > 0).toBe(true);
+ it('style preload was injected into body', async () => {
+ // preloaded1 + main + inject
+ await expect(await page.$$eval('[type="text/css"]', links => links.length)).toEqual(3);
+ // inject
+ await expect(await page.$$eval('[rel="preload"]', preloads => preloads.length)).toEqual(1);
});
- it('body background style set correctly', async () => {
+ it('body background style was not set', async () => {
await page.waitFor(4000);
const bodyStyle = await page.evaluate(() =>
getComputedStyle(document.body).getPropertyValue('background-color')
@@ -55,6 +56,7 @@ describe('insert-options', () => {
});
afterAll(() => {
+ // eslint-disable-next-line
const childProcess = require('child_process').exec;
childProcess(`kill $(lsof -t -i:3001)`);
childProcess(`kill $(lsof -t -i:5000)`);