Skip to content
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

feat(index): add checkCssChunk option and cssLinkHref function #256

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
222 changes: 116 additions & 106 deletions src/index.js
Expand Up @@ -112,6 +112,7 @@ class MiniCssExtractPlugin {
this.options = Object.assign(
{
filename: '[name].css',
checkCssChunk: true,
},
options
);
Expand Down Expand Up @@ -248,9 +249,60 @@ class MiniCssExtractPlugin {
.substring(0, hashDigestLength);
});
const { mainTemplate } = compilation;
mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => {
mainTemplate.hooks.localVars.tap(pluginName, (source, chunk, hash) => {
const chunkMap = this.getCssChunkObject(chunk);
if (Object.keys(chunkMap).length > 0) {
const chunkMaps = chunk.getChunkMaps();
const linkHrefPath = mainTemplate.getAssetPath(
JSON.stringify(this.options.chunkFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: (length) =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
chunk: {
id: '" + chunkId + "',
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
hashWithLength(length) {
const shortChunkHashMap = Object.create(null);
for (const chunkId of Object.keys(chunkMaps.hash)) {
if (typeof chunkMaps.hash[chunkId] === 'string') {
shortChunkHashMap[chunkId] = chunkMaps.hash[
chunkId
].substring(0, length);
}
}
return `" + ${JSON.stringify(
shortChunkHashMap
)}[chunkId] + "`;
},
contentHash: {
[MODULE_TYPE]: `" + ${JSON.stringify(
chunkMaps.contentHash[MODULE_TYPE]
)}[chunkId] + "`,
},
contentHashWithLength: {
[MODULE_TYPE]: (length) => {
const shortContentHashMap = {};
const contentHash = chunkMaps.contentHash[MODULE_TYPE];
for (const chunkId of Object.keys(contentHash)) {
if (typeof contentHash[chunkId] === 'string') {
shortContentHashMap[chunkId] = contentHash[
chunkId
].substring(0, length);
}
}
return `" + ${JSON.stringify(
shortContentHashMap
)}[chunkId] + "`;
},
},
name: `" + (${JSON.stringify(
chunkMaps.name
)}[chunkId]||chunkId) + "`,
},
contentHashType: MODULE_TYPE,
}
);
return Template.asString([
source,
'',
Expand All @@ -260,120 +312,78 @@ class MiniCssExtractPlugin {
chunk.ids.map((id) => `${JSON.stringify(id)}: 0`).join(',\n')
),
'}',
'',
'function cssLinkHref(chunkId) {',
Template.indent([
`var href = ${linkHrefPath};`,
`var fullhref = ${mainTemplate.requireFn}.p + href;`,
'return {href: href, fullhref: fullhref};',
]),
'}',
]);
}
return source;
});
mainTemplate.hooks.requireEnsure.tap(
pluginName,
(source, chunk, hash) => {
const chunkMap = this.getCssChunkObject(chunk);
if (Object.keys(chunkMap).length > 0) {
const chunkMaps = chunk.getChunkMaps();
const linkHrefPath = mainTemplate.getAssetPath(
JSON.stringify(this.options.chunkFilename),
{
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: (length) =>
`" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
chunk: {
id: '" + chunkId + "',
hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
hashWithLength(length) {
const shortChunkHashMap = Object.create(null);
for (const chunkId of Object.keys(chunkMaps.hash)) {
if (typeof chunkMaps.hash[chunkId] === 'string') {
shortChunkHashMap[chunkId] = chunkMaps.hash[
chunkId
].substring(0, length);
}
}
return `" + ${JSON.stringify(
shortChunkHashMap
)}[chunkId] + "`;
},
contentHash: {
[MODULE_TYPE]: `" + ${JSON.stringify(
chunkMaps.contentHash[MODULE_TYPE]
)}[chunkId] + "`,
},
contentHashWithLength: {
[MODULE_TYPE]: (length) => {
const shortContentHashMap = {};
const contentHash = chunkMaps.contentHash[MODULE_TYPE];
for (const chunkId of Object.keys(contentHash)) {
if (typeof contentHash[chunkId] === 'string') {
shortContentHashMap[chunkId] = contentHash[
chunkId
].substring(0, length);
}
}
return `" + ${JSON.stringify(
shortContentHashMap
)}[chunkId] + "`;
},
},
name: `" + (${JSON.stringify(
chunkMaps.name
)}[chunkId]||chunkId) + "`,
},
contentHashType: MODULE_TYPE,
}
);
return Template.asString([
source,
'',
`// ${pluginName} CSS loading`,
`var cssChunks = ${JSON.stringify(chunkMap)};`,
'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);',
'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {',
mainTemplate.hooks.requireEnsure.tap(pluginName, (source, chunk) => {
const chunkMap = this.getCssChunkObject(chunk);
if (Object.keys(chunkMap).length > 0) {
const checkCssChunk = this.options.checkCssChunk;
return Template.asString([
source,
'',
`// ${pluginName} CSS loading`,
checkCssChunk ? `var cssChunks = ${JSON.stringify(chunkMap)};` : '',
'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);',
`else if(installedCssChunks[chunkId] !== 0${
checkCssChunk ? ' && cssChunks[chunkId]' : ''
}) {`,
Template.indent([
'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {',
Template.indent([
'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {',
'var hrefData = cssLinkHref(chunkId);',
'var href = hrefData.href;',
'var fullhref = hrefData.fullhref;',
'var existingLinkTags = document.getElementsByTagName("link");',
'for(var i = 0; i < existingLinkTags.length; i++) {',
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();',
]),
'}',
'var existingStyleTags = document.getElementsByTagName("style");',
'for(var i = 0; i < existingStyleTags.length; i++) {',
Template.indent([
`var href = ${linkHrefPath};`,
`var fullhref = ${mainTemplate.requireFn}.p + href;`,
'var existingLinkTags = document.getElementsByTagName("link");',
'for(var i = 0; i < existingLinkTags.length; i++) {',
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();',
]),
'}',
'var existingStyleTags = document.getElementsByTagName("style");',
'for(var i = 0; i < existingStyleTags.length; i++) {',
Template.indent([
'var tag = existingStyleTags[i];',
'var dataHref = tag.getAttribute("data-href");',
'if(dataHref === href || dataHref === fullhref) return resolve();',
]),
'}',
'var linkTag = document.createElement("link");',
'linkTag.rel = "stylesheet";',
'linkTag.type = "text/css";',
'linkTag.onload = resolve;',
'linkTag.onerror = function(event) {',
Template.indent([
'var request = event && event.target && event.target.src || fullhref;',
'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");',
'err.request = request;',
'reject(err);',
]),
'};',
'linkTag.href = fullhref;',
'var head = document.getElementsByTagName("head")[0];',
'head.appendChild(linkTag);',
'var tag = existingStyleTags[i];',
'var dataHref = tag.getAttribute("data-href");',
'if(dataHref === href || dataHref === fullhref) return resolve();',
]),
'}).then(function() {',
Template.indent(['installedCssChunks[chunkId] = 0;']),
'}));',
'}',
'var linkTag = document.createElement("link");',
'linkTag.rel = "stylesheet";',
'linkTag.type = "text/css";',
'linkTag.onload = resolve;',
'linkTag.onerror = function(event) {',
Template.indent([
'var request = event && event.target && event.target.src || fullhref;',
'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");',
'err.request = request;',
'reject(err);',
]),
'};',
'linkTag.href = fullhref;',
'var head = document.getElementsByTagName("head")[0];',
'head.appendChild(linkTag);',
]),
'}',
]);
}
return source;
'}).then(function() {',
Template.indent(['installedCssChunks[chunkId] = 0;']),
'}));',
]),
'}',
]);
}
);
return source;
});
});
}

Expand Down
1 change: 1 addition & 0 deletions test/cases/runtime-without-check-csschunks/async.css
@@ -0,0 +1 @@
.async { background: blue; }
1 change: 1 addition & 0 deletions test/cases/runtime-without-check-csschunks/async.js
@@ -0,0 +1 @@
import './in-async.css';
2 changes: 2 additions & 0 deletions test/cases/runtime-without-check-csschunks/expected/1.css
@@ -0,0 +1,2 @@
.in-async { background: green; }

2 changes: 2 additions & 0 deletions test/cases/runtime-without-check-csschunks/expected/2.css
@@ -0,0 +1,2 @@
.async { background: blue; }

2 changes: 2 additions & 0 deletions test/cases/runtime-without-check-csschunks/expected/main.css
@@ -0,0 +1,2 @@
body { background: red; }