Skip to content

Commit

Permalink
fix: proof of async-loaded chunks HMR (webpack-contrib#444)
Browse files Browse the repository at this point in the history
Tests are failing
  • Loading branch information
Rulexec committed May 22, 2020
1 parent 1ffc393 commit 024cf63
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 67 deletions.
85 changes: 18 additions & 67 deletions src/hmr/hotModuleReplacement.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
func-names
*/

const normalizeUrl = require('normalize-url');

const srcByModuleId = Object.create(null);

const noDocument = typeof document === 'undefined';
Expand All @@ -32,48 +30,17 @@ function debounce(fn, time) {

function noop() {}

function getCurrentScriptUrl(moduleId) {
function getCurrentModuleChunks(moduleId) {
let src = srcByModuleId[moduleId];

if (!src) {
if (document.currentScript) {
({ src } = document.currentScript);
} else {
const scripts = document.getElementsByTagName('script');
const lastScriptTag = scripts[scripts.length - 1];

if (lastScriptTag) {
({ src } = lastScriptTag);
}
}
src = module.miniCssModuleIdToChunkIds[moduleId];

srcByModuleId[moduleId] = src;
}

return function(fileMap) {
if (!src) {
return null;
}

const splitResult = src.split(/([^\\/]+)\.js$/);
const filename = splitResult && splitResult[1];

if (!filename) {
return [src.replace('.js', '.css')];
}

if (!fileMap) {
return [src.replace('.js', '.css')];
}

return fileMap.split(',').map((mapRule) => {
const reg = new RegExp(`${filename}\\.js$`, 'g');

return normalizeUrl(
src.replace(reg, `${mapRule.replace(/{fileName}/g, filename)}.css`),
{ stripWWW: false }
);
});
return function() {
return src;
};
}

Expand Down Expand Up @@ -127,46 +94,30 @@ function updateCss(el, url) {
}
}

function getReloadUrl(href, src) {
let ret;

// eslint-disable-next-line no-param-reassign
href = normalizeUrl(href, { stripWWW: false });

// eslint-disable-next-line array-callback-return
src.some((url) => {
if (href.indexOf(src) > -1) {
ret = url;
}
});
function reloadStyle(chunkIds) {
if (!chunkIds) {
return false;
}

return ret;
}
const selector = chunkIds
.map((id) => `link[data-mini-css-chunk-id="${id}"]`)
.join(',');

function reloadStyle(src) {
const elements = document.querySelectorAll('link');
const elements = document.querySelectorAll(selector);
let loaded = false;

forEach.call(elements, (el) => {
if (!el.href) {
return;
}

const url = getReloadUrl(el.href, src);

if (!isUrlRequest(url)) {
return;
}

if (el.visited === true) {
return;
}

if (url) {
updateCss(el, url);
updateCss(el, el.href);

loaded = true;
}
loaded = true;
});

return loaded;
Expand Down Expand Up @@ -202,11 +153,11 @@ module.exports = function(moduleId, options) {
return noop;
}

const getScriptSrc = getCurrentScriptUrl(moduleId);
const getModuleChunks = getCurrentModuleChunks(moduleId);

function update() {
const src = getScriptSrc(options.filename);
const reloaded = reloadStyle(src);
const chunkIds = getModuleChunks();
const reloaded = reloadStyle(chunkIds);

if (options.locals) {
console.log('[HMR] Detected local css modules. Reload all css');
Expand All @@ -217,7 +168,7 @@ module.exports = function(moduleId, options) {
}

if (reloaded && !options.reloadAll) {
console.log('[HMR] css reload %s', src.join(' '));
console.log('[HMR] css reload %s', chunkIds.join(' '));
} else {
console.log('[HMR] Reload all css');

Expand Down
43 changes: 43 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,15 +237,50 @@ class MiniCssExtractPlugin {
.substring(0, hashDigestLength);
});

const moduleIdToChunkFiles = new Map();

compilation.hooks.afterOptimizeChunkIds.tap(pluginName, (chunks) => {
chunks.forEach((chunk) => {
const cssModules = chunk
.getModules()
.filter(
(m) =>
m.loaders &&
m.loaders.some(
(loader) =>
loader.loader.indexOf('mini-css-extract-plugin') >= 0
)
);

cssModules.forEach((m) => {
let chunkFiles = moduleIdToChunkFiles.get(m.id);
if (!chunkFiles) {
chunkFiles = new Set();
moduleIdToChunkFiles.set(m.id, chunkFiles);
}

chunkFiles.add(chunk.id);
});
});
});

const { mainTemplate } = compilation;

mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => {
const chunkMap = this.getCssChunkObject(chunk);

if (Object.keys(chunkMap).length > 0) {
const cssChunksMap = {};

moduleIdToChunkFiles.forEach((filesSet, moduleId) => {
cssChunksMap[moduleId] = Array.from(filesSet);
});

return Template.asString([
source,
'',
'// moduleId => [chunkId]',
`var miniCssModuleIdToChunkIds = ${JSON.stringify(cssChunksMap)}`,
'// object to store loaded CSS chunks',
'var installedCssChunks = {',
Template.indent(
Expand All @@ -258,6 +293,13 @@ class MiniCssExtractPlugin {
return source;
});

mainTemplate.hooks.moduleObj.tap(pluginName, (source) =>
Template.asString([
`${source},`,
'miniCssModuleIdToChunkIds: miniCssModuleIdToChunkIds',
])
);

mainTemplate.hooks.requireEnsure.tap(
pluginName,
(source, chunk, hash) => {
Expand Down Expand Up @@ -350,6 +392,7 @@ class MiniCssExtractPlugin {
]),
'}',
'var linkTag = document.createElement("link");',
`linkTag.setAttribute("data-mini-css-chunk-id", chunkId);`,
'linkTag.rel = "stylesheet";',
'linkTag.type = "text/css";',
'linkTag.onload = resolve;',
Expand Down

0 comments on commit 024cf63

Please sign in to comment.