upgrade filename runtime module to full hash module when referencing a full hash chunk

This commit is contained in:
Tobias Koppers 2021-09-02 10:00:24 +02:00
parent 179d2e00fe
commit b16568a253
17 changed files with 169 additions and 2 deletions

View File

@ -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 */
/**

View File

@ -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);

View File

@ -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,

View File

@ -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());

View File

@ -30,6 +30,7 @@ class GetChunkFilenameRuntimeModule extends RuntimeModule {
this.global = global;
this.getFilenameForChunk = getFilenameForChunk;
this.allChunks = allChunks;
this.dependentHash = true;
}
/**

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
output: {
filename: "[name].js"

View File

@ -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");
});

View File

@ -0,0 +1,3 @@
export function upper(str) {
return str.toUpperCase();
}

View File

@ -0,0 +1,5 @@
module.exports = {
findBundle: function (i, options) {
return ["a.js", "b.js", "c.js", "d.js"];
}
};

View File

@ -0,0 +1,5 @@
var supportsWorker = require("../../../helpers/supportsWorker");
module.exports = function (config) {
return supportsWorker();
};

View File

@ -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()]
};

View File

@ -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`);
});

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
output: {
filename: "[name].js"

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
entry: {
a: { import: "./index.js?a", filename: "[name].js" },

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
output: {
filename: "[name].js"

View File

@ -1,3 +1,4 @@
/** @type {import("../../../../").Configuration} */
module.exports = {
entry: {
main: {

11
types.d.ts vendored
View File

@ -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;