mirror of https://github.com/webpack/webpack.git
upgrade filename runtime module to full hash module when referencing a full hash chunk
This commit is contained in:
parent
179d2e00fe
commit
b16568a253
|
|
@ -205,6 +205,8 @@ class ChunkGraphChunk {
|
|||
this.runtimeModules = new SortableSet();
|
||||
/** @type {Set<RuntimeModule> | undefined} */
|
||||
this.fullHashModules = undefined;
|
||||
/** @type {Set<RuntimeModule> | undefined} */
|
||||
this.dependentHashModules = undefined;
|
||||
/** @type {Set<string> | undefined} */
|
||||
this.runtimeRequirements = undefined;
|
||||
/** @type {Set<string>} */
|
||||
|
|
@ -389,6 +391,20 @@ class ChunkGraph {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @param {Iterable<RuntimeModule>} modules the modules that require a full hash
|
||||
* @returns {void}
|
||||
*/
|
||||
attachDependentHashModules(chunk, modules) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
if (cgc.dependentHashModules === undefined)
|
||||
cgc.dependentHashModules = new Set();
|
||||
for (const module of modules) {
|
||||
cgc.dependentHashModules.add(module);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} oldModule the replaced module
|
||||
* @param {Module} newModule the replacing module
|
||||
|
|
@ -444,6 +460,17 @@ class ChunkGraph {
|
|||
cgc.fullHashModules.delete(/** @type {RuntimeModule} */ (oldModule));
|
||||
cgc.fullHashModules.add(/** @type {RuntimeModule} */ (newModule));
|
||||
}
|
||||
if (
|
||||
cgc.dependentHashModules !== undefined &&
|
||||
cgc.dependentHashModules.has(/** @type {RuntimeModule} */ (oldModule))
|
||||
) {
|
||||
cgc.dependentHashModules.delete(
|
||||
/** @type {RuntimeModule} */ (oldModule)
|
||||
);
|
||||
cgc.dependentHashModules.add(
|
||||
/** @type {RuntimeModule} */ (newModule)
|
||||
);
|
||||
}
|
||||
}
|
||||
oldCgm.runtimeInChunks = undefined;
|
||||
}
|
||||
|
|
@ -529,13 +556,22 @@ class ChunkGraph {
|
|||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {number} the number of module which are contained in this chunk
|
||||
* @returns {number} the number of modules which are contained in this chunk
|
||||
*/
|
||||
getNumberOfChunkModules(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.modules.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {number} the number of full hash modules which are contained in this chunk
|
||||
*/
|
||||
getNumberOfChunkFullHashModules(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.fullHashModules === undefined ? 0 : cgc.fullHashModules.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {Iterable<Module>} return the modules for this chunk
|
||||
|
|
@ -900,6 +936,23 @@ class ChunkGraph {
|
|||
ChunkGraph.clearChunkGraphForChunk(chunkB);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk to upgrade
|
||||
* @returns {void}
|
||||
*/
|
||||
upgradeDependentToFullHashModules(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
if (cgc.dependentHashModules === undefined) return;
|
||||
if (cgc.fullHashModules === undefined) {
|
||||
cgc.fullHashModules = cgc.dependentHashModules;
|
||||
} else {
|
||||
for (const m of cgc.dependentHashModules) {
|
||||
cgc.fullHashModules.add(m);
|
||||
}
|
||||
cgc.dependentHashModules = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Module} module the checked module
|
||||
* @param {Chunk} chunk the checked chunk
|
||||
|
|
@ -952,6 +1005,18 @@ class ChunkGraph {
|
|||
cgc.fullHashModules.add(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the new chunk
|
||||
* @param {RuntimeModule} module the module that require a full hash
|
||||
* @returns {void}
|
||||
*/
|
||||
addDependentHashModuleToChunk(chunk, module) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
if (cgc.dependentHashModules === undefined)
|
||||
cgc.dependentHashModules = new Set();
|
||||
cgc.dependentHashModules.add(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the new chunk
|
||||
* @param {Module} module the entry module
|
||||
|
|
@ -1128,6 +1193,15 @@ class ChunkGraph {
|
|||
return cgc.fullHashModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Chunk} chunk the chunk
|
||||
* @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
|
||||
*/
|
||||
getChunkDependentHashModulesIterable(chunk) {
|
||||
const cgc = this._getChunkGraphChunk(chunk);
|
||||
return cgc.dependentHashModules;
|
||||
}
|
||||
|
||||
/** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2879,6 +2879,8 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
chunkGraph.connectChunkAndRuntimeModule(chunk, module);
|
||||
if (module.fullHash) {
|
||||
chunkGraph.addFullHashModuleToChunk(chunk, module);
|
||||
} else if (module.dependentHash) {
|
||||
chunkGraph.addDependentHashModuleToChunk(chunk, module);
|
||||
}
|
||||
|
||||
// attach runtime module
|
||||
|
|
@ -3344,8 +3346,13 @@ Or do you want to use the entrypoints '${name}' and '${runtime}' independently o
|
|||
if (remaining > 0) {
|
||||
const readyChunks = [];
|
||||
for (const chunk of runtimeChunks) {
|
||||
const hasFullHashModules =
|
||||
chunkGraph.getNumberOfChunkFullHashModules(chunk) !== 0;
|
||||
const info = runtimeChunksMap.get(chunk);
|
||||
for (const otherInfo of info.referencedBy) {
|
||||
if (hasFullHashModules) {
|
||||
chunkGraph.upgradeDependentToFullHashModules(otherInfo.chunk);
|
||||
}
|
||||
remaining--;
|
||||
if (--otherInfo.remaining === 0) {
|
||||
readyChunks.push(otherInfo.chunk);
|
||||
|
|
|
|||
|
|
@ -495,6 +495,7 @@ class HotModuleReplacementPlugin {
|
|||
let newModules;
|
||||
let newRuntimeModules;
|
||||
let newFullHashModules;
|
||||
let newDependentHashModules;
|
||||
let newRuntime;
|
||||
let removedFromRuntime;
|
||||
const currentChunk = find(
|
||||
|
|
@ -521,6 +522,13 @@ class HotModuleReplacementPlugin {
|
|||
Array.from(fullHashModules).filter(module =>
|
||||
updatedModules.has(module, currentChunk)
|
||||
);
|
||||
const dependentHashModules =
|
||||
chunkGraph.getChunkDependentHashModulesIterable(currentChunk);
|
||||
newDependentHashModules =
|
||||
dependentHashModules &&
|
||||
Array.from(dependentHashModules).filter(module =>
|
||||
updatedModules.has(module, currentChunk)
|
||||
);
|
||||
removedFromRuntime = subtractRuntime(oldRuntime, newRuntime);
|
||||
} else {
|
||||
// chunk has completely removed
|
||||
|
|
@ -607,6 +615,12 @@ class HotModuleReplacementPlugin {
|
|||
newFullHashModules
|
||||
);
|
||||
}
|
||||
if (newDependentHashModules) {
|
||||
chunkGraph.attachDependentHashModules(
|
||||
hotUpdateChunk,
|
||||
newDependentHashModules
|
||||
);
|
||||
}
|
||||
const renderManifest = compilation.getRenderManifest({
|
||||
chunk: hotUpdateChunk,
|
||||
hash: records.hash,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class RuntimeModule extends Module {
|
|||
/** @type {ChunkGraph} */
|
||||
this.chunkGraph = undefined;
|
||||
this.fullHash = false;
|
||||
this.dependentHash = false;
|
||||
/** @type {string} */
|
||||
this._cachedGeneratedCode = undefined;
|
||||
}
|
||||
|
|
@ -107,7 +108,7 @@ class RuntimeModule extends Module {
|
|||
hash.update(this.name);
|
||||
hash.update(`${this.stage}`);
|
||||
try {
|
||||
if (this.fullHash) {
|
||||
if (this.fullHash || this.dependentHash) {
|
||||
// Do not use getGeneratedCode here, because i. e. compilation hash might be not
|
||||
// ready at this point. We will cache it later instead.
|
||||
hash.update(this.generate());
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
|
|||
this.global = global;
|
||||
this.getFilenameForChunk = getFilenameForChunk;
|
||||
this.allChunks = allChunks;
|
||||
this.dependentHash = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
import { Worker } from "worker_threads";
|
||||
|
||||
it("should allow to create a WebWorker", async () => {
|
||||
const worker = new Worker(
|
||||
new URL("./worker.js" + __resourceQuery, import.meta.url)
|
||||
);
|
||||
worker.postMessage("ok");
|
||||
const result = await new Promise(resolve => {
|
||||
worker.on("message", data => {
|
||||
resolve(data);
|
||||
});
|
||||
});
|
||||
expect(result).toBe("data: OK, thanks");
|
||||
await worker.terminate();
|
||||
});
|
||||
|
||||
it("should allow to share chunks", async () => {
|
||||
const { upper } = await import("./module");
|
||||
expect(upper("ok")).toBe("OK");
|
||||
});
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export function upper(str) {
|
||||
return str.toUpperCase();
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
findBundle: function (i, options) {
|
||||
return ["a.js", "b.js", "c.js", "d.js"];
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
var supportsWorker = require("../../../helpers/supportsWorker");
|
||||
|
||||
module.exports = function (config) {
|
||||
return supportsWorker();
|
||||
};
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
const webpack = require("../../../../");
|
||||
|
||||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
entry: {
|
||||
a: { import: "./index.js?a", filename: "[name].js" },
|
||||
b: { import: "./index.js?b", filename: "[name].js" },
|
||||
c: { import: "./index.js?c", filename: "[name].js" },
|
||||
d: { import: "./index.js?d", filename: "[name].js" }
|
||||
},
|
||||
output: {
|
||||
filename: "[name].[contenthash].js"
|
||||
},
|
||||
plugins: [new webpack.HotModuleReplacementPlugin()]
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { parentPort } from "worker_threads";
|
||||
|
||||
parentPort.on("message", async data => {
|
||||
const { upper } = await import("./module");
|
||||
parentPort.postMessage(`data: ${upper(data)}, thanks`);
|
||||
});
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
entry: {
|
||||
a: { import: "./index.js?a", filename: "[name].js" },
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
output: {
|
||||
filename: "[name].js"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/** @type {import("../../../../").Configuration} */
|
||||
module.exports = {
|
||||
entry: {
|
||||
main: {
|
||||
|
|
|
|||
|
|
@ -767,6 +767,10 @@ declare class ChunkGraph {
|
|||
attachModules(chunk: Chunk, modules: Iterable<Module>): void;
|
||||
attachRuntimeModules(chunk: Chunk, modules: Iterable<RuntimeModule>): void;
|
||||
attachFullHashModules(chunk: Chunk, modules: Iterable<RuntimeModule>): void;
|
||||
attachDependentHashModules(
|
||||
chunk: Chunk,
|
||||
modules: Iterable<RuntimeModule>
|
||||
): void;
|
||||
replaceModule(oldModule: Module, newModule: Module): void;
|
||||
isModuleInChunk(module: Module, chunk: Chunk): boolean;
|
||||
isModuleInChunkGroup(module: Module, chunkGroup: ChunkGroup): boolean;
|
||||
|
|
@ -780,6 +784,7 @@ declare class ChunkGraph {
|
|||
getNumberOfModuleChunks(module: Module): number;
|
||||
getModuleRuntimes(module: Module): RuntimeSpecSet;
|
||||
getNumberOfChunkModules(chunk: Chunk): number;
|
||||
getNumberOfChunkFullHashModules(chunk: Chunk): number;
|
||||
getChunkModulesIterable(chunk: Chunk): Iterable<Module>;
|
||||
getChunkModulesIterableBySourceType(
|
||||
chunk: Chunk,
|
||||
|
|
@ -831,6 +836,7 @@ declare class ChunkGraph {
|
|||
): number;
|
||||
canChunksBeIntegrated(chunkA: Chunk, chunkB: Chunk): boolean;
|
||||
integrateChunks(chunkA: Chunk, chunkB: Chunk): void;
|
||||
upgradeDependentToFullHashModules(chunk: Chunk): void;
|
||||
isEntryModuleInChunk(module: Module, chunk: Chunk): boolean;
|
||||
connectChunkAndEntryModule(
|
||||
chunk: Chunk,
|
||||
|
|
@ -839,6 +845,7 @@ declare class ChunkGraph {
|
|||
): void;
|
||||
connectChunkAndRuntimeModule(chunk: Chunk, module: RuntimeModule): void;
|
||||
addFullHashModuleToChunk(chunk: Chunk, module: RuntimeModule): void;
|
||||
addDependentHashModuleToChunk(chunk: Chunk, module: RuntimeModule): void;
|
||||
disconnectChunkAndEntryModule(chunk: Chunk, module: Module): void;
|
||||
disconnectChunkAndRuntimeModule(chunk: Chunk, module: RuntimeModule): void;
|
||||
disconnectEntryModule(module: Module): void;
|
||||
|
|
@ -856,6 +863,9 @@ declare class ChunkGraph {
|
|||
getChunkFullHashModulesSet(
|
||||
chunk: Chunk
|
||||
): undefined | ReadonlySet<RuntimeModule>;
|
||||
getChunkDependentHashModulesIterable(
|
||||
chunk: Chunk
|
||||
): undefined | Iterable<RuntimeModule>;
|
||||
getChunkEntryModulesWithChunkGroupIterable(
|
||||
chunk: Chunk
|
||||
): Iterable<[Module, undefined | Entrypoint]>;
|
||||
|
|
@ -9779,6 +9789,7 @@ declare class RuntimeModule extends Module {
|
|||
chunk: Chunk;
|
||||
chunkGraph: ChunkGraph;
|
||||
fullHash: boolean;
|
||||
dependentHash: boolean;
|
||||
attach(compilation: Compilation, chunk: Chunk, chunkGraph?: ChunkGraph): void;
|
||||
generate(): string;
|
||||
getGeneratedCode(): string;
|
||||
|
|
|
|||
Loading…
Reference in New Issue