diff --git a/README.md b/README.md index 159e11e8..ba286d08 100644 --- a/README.md +++ b/README.md @@ -529,6 +529,13 @@ module.exports = { For long term caching use `filename: "[contenthash].css"`. Optionally add `[name]`. +#### rel="preload" support + +On browsers that support ``, then CSS links will be preloaded by default. +This is both to improve page load performance, and addresess Chrome Lighthouse SEO performance audits requiring the use of rel="preload" with asynchronous chunks. + +-[Lighthouse article](https://developers.google.com/web/tools/lighthouse/audits/preload) + **webpack.config.js** ```js diff --git a/src/index.js b/src/index.js index d9f6bf2d..37050b6d 100644 --- a/src/index.js +++ b/src/index.js @@ -321,10 +321,13 @@ class MiniCssExtractPlugin { } ); + 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]) {', @@ -338,7 +341,7 @@ class MiniCssExtractPlugin { 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");', @@ -350,8 +353,8 @@ class MiniCssExtractPlugin { ]), '}', '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([ @@ -380,7 +383,18 @@ class MiniCssExtractPlugin { '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 be56e01d..da0203e7 100644 --- a/test/HMR.test.js +++ b/test/HMR.test.js @@ -27,7 +27,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`] = `""`;