mirror of https://github.com/webpack/webpack.git
fix: entryChunk depends on the runtimeChunk hash
This commit is contained in:
parent
67379fe33d
commit
5a72fb9bec
|
@ -8,13 +8,16 @@
|
|||
const { ConcatSource } = require("webpack-sources");
|
||||
const { HotUpdateChunk, RuntimeGlobals } = require("..");
|
||||
const Template = require("../Template");
|
||||
const {
|
||||
createChunkHashHandler,
|
||||
getChunkInfo
|
||||
} = require("../javascript/ChunkFormatHelpers");
|
||||
const { getAllChunks } = require("../javascript/ChunkHelpers");
|
||||
const {
|
||||
chunkHasJs,
|
||||
getChunkFilenameTemplate,
|
||||
getCompilationHooks
|
||||
} = require("../javascript/JavascriptModulesPlugin");
|
||||
const { updateHashForEntryStartup } = require("../javascript/StartupHelpers");
|
||||
const { getUndoPath } = require("../util/identifier");
|
||||
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
|
@ -27,28 +30,6 @@ const { getUndoPath } = require("../util/identifier");
|
|||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */
|
||||
|
||||
/**
|
||||
* Gets information about a chunk including its entries and runtime chunk
|
||||
* @param {Chunk} chunk The chunk to get information for
|
||||
* @param {ChunkGraph} chunkGraph The chunk graph containing the chunk
|
||||
* @returns {{entries: Array<[Module, Entrypoint | undefined]>, runtimeChunk: Chunk|null}} Object containing chunk entries and runtime chunk
|
||||
*/
|
||||
function getChunkInfo(chunk, chunkGraph) {
|
||||
const entries = [
|
||||
...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||
];
|
||||
const runtimeChunk =
|
||||
entries.length > 0
|
||||
? /** @type {Entrypoint[][]} */
|
||||
(entries)[0][1].getRuntimeChunk()
|
||||
: null;
|
||||
|
||||
return {
|
||||
entries,
|
||||
runtimeChunk
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Compilation} compilation the compilation instance
|
||||
* @param {Chunk} chunk the chunk
|
||||
|
@ -287,19 +268,7 @@ class ModuleChunkFormatPlugin {
|
|||
}
|
||||
return source;
|
||||
});
|
||||
hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, { chunkGraph }) => {
|
||||
if (chunk.hasRuntime()) return;
|
||||
const { entries, runtimeChunk } = getChunkInfo(chunk, chunkGraph);
|
||||
hash.update(PLUGIN_NAME);
|
||||
hash.update("1");
|
||||
if (runtimeChunk && runtimeChunk.hash) {
|
||||
// Any change to runtimeChunk should trigger a hash update,
|
||||
// we shouldn't depend on or inspect its internal implementation.
|
||||
// import __webpack_require__ from "./runtime-main.e9400aee33633a3973bd.js";
|
||||
hash.update(runtimeChunk.hash);
|
||||
}
|
||||
updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
|
||||
});
|
||||
hooks.chunkHash.tap(PLUGIN_NAME, createChunkHashHandler(PLUGIN_NAME));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Natsu @xiaoxiaojx
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { updateHashForEntryStartup } = require("./StartupHelpers");
|
||||
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Entrypoint")} Entrypoint */
|
||||
/** @typedef {import("../util/Hash")} Hash */
|
||||
/** @typedef {import("../Compilation").ChunkHashContext} ChunkHashContext */
|
||||
|
||||
/**
|
||||
* Gets information about a chunk including its entries and runtime chunk
|
||||
* @param {Chunk} chunk The chunk to get information for
|
||||
* @param {ChunkGraph} chunkGraph The chunk graph containing the chunk
|
||||
* @returns {{entries: Array<[Module, Entrypoint | undefined]>, runtimeChunk: Chunk|null}} Object containing chunk entries and runtime chunk
|
||||
*/
|
||||
function getChunkInfo(chunk, chunkGraph) {
|
||||
const entries = [
|
||||
...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||
];
|
||||
const runtimeChunk =
|
||||
entries.length > 0
|
||||
? /** @type {Entrypoint[][]} */
|
||||
(entries)[0][1].getRuntimeChunk()
|
||||
: null;
|
||||
|
||||
return {
|
||||
entries,
|
||||
runtimeChunk
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chunk hash handler
|
||||
* @param {string} name The name of the chunk
|
||||
* @returns {(chunk: Chunk, hash: Hash, { chunkGraph }: ChunkHashContext) => void} The chunk hash handler
|
||||
*/
|
||||
function createChunkHashHandler(name) {
|
||||
/**
|
||||
* @param {Chunk} chunk The chunk to get information for
|
||||
* @param {Hash} hash The hash to update
|
||||
* @param {ChunkHashContext} chunkHashContext The chunk hash context
|
||||
* @returns {void}
|
||||
*/
|
||||
return (chunk, hash, { chunkGraph }) => {
|
||||
if (chunk.hasRuntime()) return;
|
||||
const { entries, runtimeChunk } = getChunkInfo(chunk, chunkGraph);
|
||||
hash.update(name);
|
||||
hash.update("1");
|
||||
if (runtimeChunk && runtimeChunk.hash) {
|
||||
// https://github.com/webpack/webpack/issues/19439
|
||||
// Any change to runtimeChunk should trigger a hash update,
|
||||
// we shouldn't depend on or inspect its internal implementation.
|
||||
// import __webpack_require__ from "./runtime-main.e9400aee33633a3973bd.js";
|
||||
hash.update(runtimeChunk.hash);
|
||||
}
|
||||
updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createChunkHashHandler,
|
||||
getChunkInfo
|
||||
};
|
|
@ -9,14 +9,15 @@ const { ConcatSource, RawSource } = require("webpack-sources");
|
|||
const RuntimeGlobals = require("../RuntimeGlobals");
|
||||
const Template = require("../Template");
|
||||
const { getUndoPath } = require("../util/identifier");
|
||||
const {
|
||||
createChunkHashHandler,
|
||||
getChunkInfo
|
||||
} = require("./ChunkFormatHelpers");
|
||||
const {
|
||||
getChunkFilenameTemplate,
|
||||
getCompilationHooks
|
||||
} = require("./JavascriptModulesPlugin");
|
||||
const {
|
||||
generateEntryStartup,
|
||||
updateHashForEntryStartup
|
||||
} = require("./StartupHelpers");
|
||||
const { generateEntryStartup } = require("./StartupHelpers");
|
||||
|
||||
/** @typedef {import("../Chunk")} Chunk */
|
||||
/** @typedef {import("../Compiler")} Compiler */
|
||||
|
@ -59,13 +60,8 @@ class CommonJsChunkFormatPlugin {
|
|||
Template.renderChunkRuntimeModules(runtimeModules, renderContext)
|
||||
);
|
||||
}
|
||||
const entries = [
|
||||
...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||
];
|
||||
if (entries.length > 0) {
|
||||
const runtimeChunk =
|
||||
/** @type {Entrypoint} */
|
||||
(entries[0][1]).getRuntimeChunk();
|
||||
const { entries, runtimeChunk } = getChunkInfo(chunk, chunkGraph);
|
||||
if (runtimeChunk) {
|
||||
const currentOutputName = compilation
|
||||
.getPath(
|
||||
getChunkFilenameTemplate(chunk, compilation.outputOptions),
|
||||
|
@ -144,15 +140,8 @@ class CommonJsChunkFormatPlugin {
|
|||
}
|
||||
return source;
|
||||
});
|
||||
hooks.chunkHash.tap(PLUGIN_NAME, (chunk, hash, { chunkGraph }) => {
|
||||
if (chunk.hasRuntime()) return;
|
||||
hash.update(PLUGIN_NAME);
|
||||
hash.update("1");
|
||||
const entries = [
|
||||
...chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
|
||||
];
|
||||
updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
|
||||
});
|
||||
|
||||
hooks.chunkHash.tap(PLUGIN_NAME, createChunkHashHandler(PLUGIN_NAME));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export var value = "0";
|
|
@ -0,0 +1,2 @@
|
|||
export var value = "0";
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import { react } from "./react";
|
||||
|
||||
it("should work where an ESM entryChunk depends on the runtimeChunk", async function (done) {
|
||||
const mainChunk = STATS_JSON.chunks.find((chunk) => chunk.id === "main");
|
||||
const runtimeChunk = STATS_JSON.chunks.find((chunk) => chunk.id === "runtime-main");
|
||||
const dynamic1Chunk = STATS_JSON.chunks.find((chunk) => chunk.id === "dynamic-1_js");
|
||||
const dynamic2Chunk = STATS_JSON.chunks.find((chunk) => chunk.id === "dynamic-2_js");
|
||||
const reactChunk = STATS_JSON.chunks.find((chunk) => chunk.id === "react");
|
||||
expect(mainChunk).toBeDefined();
|
||||
expect(react).toBe("react");
|
||||
|
||||
await import('./dynamic-1').then(console.log)
|
||||
await import('./dynamic-2').then(console.log)
|
||||
|
||||
if (WATCH_STEP === "0") {
|
||||
STATE.mainChunkHash = mainChunk.hash;
|
||||
STATE.dynamic1ChunkHash = dynamic1Chunk.hash;
|
||||
STATE.dynamic2ChunkHash = dynamic2Chunk.hash;
|
||||
STATE.runtimeChunkHash = runtimeChunk.hash;
|
||||
STATE.reactChunkHash = reactChunk.hash;
|
||||
} else {
|
||||
// async dynamic2Chunk needn't be updated
|
||||
expect(dynamic2Chunk.hash).toBe(STATE.dynamic2ChunkHash);
|
||||
// initial reactChunk is needn't be updated
|
||||
expect(reactChunk.hash).toBe(STATE.reactChunkHash);
|
||||
|
||||
|
||||
// initial mainChunk need to be updated
|
||||
expect(mainChunk.hash).not.toBe(STATE.mainChunkHash);
|
||||
// async dynamic1Chunk need to be updated
|
||||
expect(dynamic1Chunk.hash).not.toBe(STATE.dynamic1ChunkHash);
|
||||
// runtime runtimeChunk need to be updated
|
||||
expect(runtimeChunk.hash).not.toBe(STATE.runtimeChunkHash);
|
||||
}
|
||||
done()
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
export const react = "react";
|
|
@ -0,0 +1,3 @@
|
|||
export var value = "1";
|
||||
|
||||
import("./dynamic-2").then(console.log)
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
bundlePath: /^main\./
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
devtool: false,
|
||||
mode: "development",
|
||||
target: "node",
|
||||
optimization: {
|
||||
minimize: false,
|
||||
splitChunks: {
|
||||
chunks: "all",
|
||||
minSize: 1,
|
||||
cacheGroups: {
|
||||
react: {
|
||||
test: /react/,
|
||||
name: "react",
|
||||
chunks: "all",
|
||||
priority: 100
|
||||
}
|
||||
}
|
||||
},
|
||||
runtimeChunk: {
|
||||
/**
|
||||
* @param {import("../../../../").Entrypoint} entrypoint The entrypoint to generate runtime chunk name for
|
||||
* @returns {string} The generated runtime chunk name
|
||||
*/
|
||||
name: (entrypoint) => `runtime-${entrypoint.name}`
|
||||
}
|
||||
},
|
||||
output: {
|
||||
filename: "[name].[contenthash].js",
|
||||
chunkFilename: "[name].[contenthash].js"
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue