Skip to content

feat: preload css #300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {',
Expand All @@ -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++) {',
Expand All @@ -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([
Expand Down Expand Up @@ -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);',
]),
'}',
]),
'}));',
]),
'}',
Expand Down
3 changes: 2 additions & 1 deletion test/HMR.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ describe('HMR', () => {

jest.spyOn(Date, 'now').mockImplementation(() => 1479427200000);

document.head.innerHTML = '<link rel="stylesheet" href="/dist/main.css" />';
document.head.innerHTML =
'<link rel="preload" as="style" href="/dist/main.css" />';
document.body.innerHTML = '<script src="/dist/main.js"></script>';
});

Expand Down
12 changes: 6 additions & 6 deletions test/__snapshots__/HMR.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`HMR should handle error event 1`] = `"[HMR] css reload %s"`;

exports[`HMR should handle error event 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;
exports[`HMR should handle error event 2`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"/dist/main.css\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;

exports[`HMR should reloads with # link href 1`] = `"[HMR] css reload %s"`;

Expand All @@ -18,22 +18,22 @@ exports[`HMR should reloads with link without href 2`] = `"<link rel=\\"styleshe

exports[`HMR should reloads with locals 1`] = `"[HMR] Detected local css modules. Reload all css"`;

exports[`HMR should reloads with locals 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;
exports[`HMR should reloads with locals 2`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"/dist/main.css\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;

exports[`HMR should reloads with non http/https link href 1`] = `"[HMR] css reload %s"`;

exports[`HMR should reloads with non http/https link href 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\"><link rel=\\"shortcut icon\\" href=\\"data:;base64,=\\">"`;

exports[`HMR should reloads with reloadAll option 1`] = `"[HMR] Reload all css"`;

exports[`HMR should reloads with reloadAll option 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;
exports[`HMR should reloads with reloadAll option 2`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"/dist/main.css\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;

exports[`HMR should works 1`] = `"[HMR] css reload %s"`;

exports[`HMR should works 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;
exports[`HMR should works 2`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"/dist/main.css\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;

exports[`HMR should works with multiple updates 1`] = `"[HMR] css reload %s"`;

exports[`HMR should works with multiple updates 2`] = `"<link rel=\\"stylesheet\\" href=\\"/dist/main.css\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;
exports[`HMR should works with multiple updates 2`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"/dist/main.css\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\">"`;

exports[`HMR should works with multiple updates 3`] = `"<link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200000\\"><link rel=\\"stylesheet\\" href=\\"http://localhost/dist/main.css?1479427200001\\">"`;
exports[`HMR should works with multiple updates 3`] = `"<link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200000\\"><link rel=\\"preload\\" as=\\"style\\" href=\\"http://localhost/dist/main.css?1479427200001\\">"`;
23 changes: 12 additions & 11 deletions test/cases/insert-function/expected/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand All @@ -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++) {
Expand All @@ -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;
Expand All @@ -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);
/******/ }
/******/ }));
/******/ }
/******/
Expand Down
4 changes: 3 additions & 1 deletion test/cases/insert-function/webpack.config.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ module.exports = {
new Self({
filename: '[name].css',
chunkFilename: '[id].css',
insert: 'body',
insert: (linkTag) => {
document.head.appendChild(linkTag)
},
}),
],
devServer: {
Expand Down
19 changes: 13 additions & 6 deletions test/cases/insert-string/expected/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand All @@ -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++) {
Expand All @@ -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;
Expand All @@ -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);
/******/ }
/******/ }));
/******/ }
/******/
Expand Down
2 changes: 1 addition & 1 deletion test/cases/insert-string/webpack.config.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ module.exports = {
new Self({
filename: '[name].css',
chunkFilename: '[id].css',
insert: 'body',
insert: '(linkTag) => { document.head.appendChild(linkTag) }',
}),
],
devServer: {
Expand Down
2 changes: 1 addition & 1 deletion test/cases/publicpath-emptystring/expected/main.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
background: red;
background-image: url(cd0bb358c45b584743d8ce4991777c42.svg);
background-image: url(c9e192c015437a21dea1faa1d30f4941.svg);
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
background: green;
background-image: url(../../cd0bb358c45b584743d8ce4991777c42.svg);
background-image: url(../../c9e192c015437a21dea1faa1d30f4941.svg);
}

2 changes: 1 addition & 1 deletion test/cases/publicpath-function/expected/nested/style.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
background: red;
background-image: url(../cd0bb358c45b584743d8ce4991777c42.svg);
background-image: url(../c9e192c015437a21dea1faa1d30f4941.svg);
}

2 changes: 1 addition & 1 deletion test/cases/publicpath-trailing-slash/expected/main.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
background: red;
background-image: url(/static/img/cd0bb358c45b584743d8ce4991777c42.svg);
background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
}

2 changes: 1 addition & 1 deletion test/cases/simple-publicpath/expected/main.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body {
background: red;
background-image: url(/static/img/cd0bb358c45b584743d8ce4991777c42.svg);
background-image: url(/static/img/c9e192c015437a21dea1faa1d30f4941.svg);
}

2 changes: 1 addition & 1 deletion test/cases/split-chunks/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// eslint-disable-next-line import/no-extraneous-dependencies
// eslint-disable-next-line
import 'bootstrap.css';
import './style.css';
24 changes: 13 additions & 11 deletions test/inject-option.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
);
Expand All @@ -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')
Expand All @@ -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)`);
Expand Down