add entry[x].runtime option to allow runtime chunk per entry

This commit is contained in:
Tobias Koppers 2020-07-21 10:22:10 +02:00
parent 034cd23209
commit b3466e996b
7 changed files with 98 additions and 44 deletions

View File

@ -100,6 +100,10 @@ export type LibraryType =
* If `output.libraryTarget` is set to umd and `output.library` is set, setting this to true will name the AMD module.
*/
export type UmdNamedDefine = boolean;
/**
* The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
*/
export type EntryRuntime = string;
/**
* An entry point without name.
*/
@ -798,6 +802,10 @@ export interface EntryDescription {
* Options for library.
*/
library?: LibraryOptions;
/**
* The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
*/
runtime?: EntryRuntime;
}
/**
* Options for library.
@ -2008,6 +2016,10 @@ export interface EntryDescriptionNormalized {
* Options for library.
*/
library?: LibraryOptions;
/**
* The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
*/
runtime?: EntryRuntime;
}
/**
* Multiple entry bundles are created. The key is the entry name. The value is an entry description object.

View File

@ -1743,7 +1743,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
chunk.filenameTemplate = options.filename;
}
const entrypoint = new Entrypoint(name);
if (!options.dependOn) entrypoint.setRuntimeChunk(chunk);
if (!options.dependOn && !options.runtime) {
entrypoint.setRuntimeChunk(chunk);
}
entrypoint.setEntrypointChunk(chunk);
this.namedChunkGroups.set(name, entrypoint);
this.entrypoints.set(name, entrypoint);
this.chunkGroups.push(entrypoint);
@ -1788,7 +1791,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
for (const [
name,
{
options: { dependOn }
options: { dependOn, runtime }
}
] of this.entries) {
if (dependOn) {
@ -1802,6 +1805,13 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si
}
connectChunkGroupParentAndChild(dependency, entry);
}
} else if (runtime) {
const entry = this.entrypoints.get(name);
const chunk = this.addChunk(runtime);
chunk.preventIntegration = true;
entry.unshiftChunk(chunk);
chunk.addGroup(entry);
entry.setRuntimeChunk(chunk);
}
}
buildChunkGraph(this, chunkGraphInit);

View File

@ -23,7 +23,9 @@ class Entrypoint extends ChunkGroup {
constructor(name) {
super(name);
/** @type {Chunk=} */
this.runtimeChunk = undefined;
this._runtimeChunk = undefined;
/** @type {Chunk=} */
this._entrypointChunk = undefined;
}
/**
@ -40,7 +42,7 @@ class Entrypoint extends ChunkGroup {
* @returns {void}
*/
setRuntimeChunk(chunk) {
this.runtimeChunk = chunk;
this._runtimeChunk = chunk;
}
/**
@ -48,20 +50,39 @@ class Entrypoint extends ChunkGroup {
* @returns {Chunk | null} returns the runtime chunk or null if there is none
*/
getRuntimeChunk() {
if (this.runtimeChunk) return this.runtimeChunk;
if (this._runtimeChunk) return this._runtimeChunk;
for (const parent of this.parentsIterable) {
if (parent instanceof Entrypoint) return parent.getRuntimeChunk();
}
return null;
}
/**
* Sets the chunk with the entrypoint modules for an entrypoint.
* @param {Chunk} chunk the chunk being set as the entrypoint chunk.
* @returns {void}
*/
setEntrypointChunk(chunk) {
this._entrypointChunk = chunk;
}
/**
* Returns the chunk which contains the entrypoint modules
* (or at least the execution of them)
* @returns {Chunk} chunk
*/
getEntrypointChunk() {
return this._entrypointChunk;
}
/**
* @param {Chunk} oldChunk chunk to be replaced
* @param {Chunk} newChunk New chunk that will be replaced with
* @returns {boolean} returns true if the replacement was successful
*/
replaceChunk(oldChunk, newChunk) {
if (this.runtimeChunk === oldChunk) this.runtimeChunk = newChunk;
if (this._runtimeChunk === oldChunk) this._runtimeChunk = newChunk;
if (this._entrypointChunk === oldChunk) this._entrypointChunk = newChunk;
return super.replaceChunk(oldChunk, newChunk);
}
}

View File

@ -208,7 +208,7 @@ const visitModules = (
} else {
// The application may start here: We start with an empty list of available modules
chunkGroupInfo.minAvailableModules = EMPTY_SET;
const chunk = chunkGroup.chunks[0];
const chunk = chunkGroup.getEntrypointChunk();
for (const module of modules) {
queue.push({
action: ADD_AND_ENTER_MODULE,

View File

@ -5,8 +5,6 @@
"use strict";
const { STAGE_ADVANCED } = require("../OptimizationStages");
/** @typedef {import("../Compiler")} Compiler */
class RuntimeChunkPlugin {
@ -24,34 +22,17 @@ class RuntimeChunkPlugin {
*/
apply(compiler) {
compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => {
compilation.hooks.optimizeChunks.tap(
{
name: "RuntimeChunkPlugin",
stage: STAGE_ADVANCED
},
() => {
const chunkGraph = compilation.chunkGraph;
for (const entrypoint of compilation.entrypoints.values()) {
const chunk = entrypoint.getRuntimeChunk();
// Only insert a runtime chunk when the current runtime chunk is part of the entrypoint
if (!entrypoint.chunks.includes(chunk)) continue;
compilation.hooks.addEntry.tap(
"RuntimeChunkPlugin",
(_, { name: entryName }) => {
const data = compilation.entries.get(entryName);
if (data.options.runtime === undefined && !data.options.dependOn) {
// Determine runtime chunk name
let name = this.options.name;
if (typeof name === "function") {
name = name(entrypoint);
}
// Avoid adding runtime chunk twice
if (
chunkGraph.getNumberOfChunkModules(chunk) > 0 ||
!chunk.preventIntegration ||
chunk.name !== name
) {
const newChunk = compilation.addChunk(name);
newChunk.preventIntegration = true;
entrypoint.unshiftChunk(newChunk);
newChunk.addGroup(entrypoint);
entrypoint.setRuntimeChunk(newChunk);
name = name({ name: entryName });
}
data.options.runtime = name;
}
}
);

View File

@ -217,6 +217,9 @@
},
"library": {
"$ref": "#/definitions/LibraryOptions"
},
"runtime": {
"$ref": "#/definitions/EntryRuntime"
}
},
"required": ["import"]
@ -253,6 +256,9 @@
},
"library": {
"$ref": "#/definitions/LibraryOptions"
},
"runtime": {
"$ref": "#/definitions/EntryRuntime"
}
}
},
@ -313,6 +319,11 @@
]
}
},
"EntryRuntime": {
"description": "The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.",
"type": "string",
"minLength": 1
},
"EntryStatic": {
"description": "A static entry description.",
"anyOf": [

41
types.d.ts vendored
View File

@ -935,7 +935,7 @@ declare class Compilation {
Dependency,
{ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>
],
void
@ -945,7 +945,7 @@ declare class Compilation {
Dependency,
{ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>,
Error
],
@ -956,7 +956,7 @@ declare class Compilation {
Dependency,
{ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>,
Module
],
@ -1185,7 +1185,7 @@ declare class Compilation {
| string
| ({ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>),
callback: (err?: WebpackError, result?: Module) => void
): void;
@ -1194,7 +1194,7 @@ declare class Compilation {
dependency: Dependency,
options: { name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>,
callback: (err?: WebpackError, result?: Module) => void
): void;
@ -2244,7 +2244,7 @@ declare interface EntryData {
*/
options: { name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>;
}
declare abstract class EntryDependency extends ModuleDependency {}
@ -2272,6 +2272,11 @@ declare interface EntryDescription {
* Options for library.
*/
library?: LibraryOptions;
/**
* The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
*/
runtime?: string;
}
/**
@ -2297,6 +2302,11 @@ declare interface EntryDescriptionNormalized {
* Options for library.
*/
library?: LibraryOptions;
/**
* The name of the runtime chunk. If set a runtime chunk with this name is created or an existing entrypoint is used as runtime.
*/
runtime?: string;
}
type EntryItem = string | [string, ...string[]];
type EntryNormalized =
@ -2321,7 +2331,7 @@ declare class EntryPlugin {
| string
| ({ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>)
);
context: string;
@ -2330,7 +2340,7 @@ declare class EntryPlugin {
| string
| ({ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>);
/**
@ -2343,7 +2353,7 @@ declare class EntryPlugin {
| string
| ({ name: string } & Pick<
EntryDescriptionNormalized,
"filename" | "dependOn" | "library"
"filename" | "dependOn" | "library" | "runtime"
>)
): EntryDependency;
}
@ -2356,8 +2366,6 @@ declare interface EntryStaticNormalized {
[index: string]: EntryDescriptionNormalized;
}
declare abstract class Entrypoint extends ChunkGroup {
runtimeChunk: Chunk;
/**
* Sets the runtimeChunk for an entrypoint.
*/
@ -2367,6 +2375,17 @@ declare abstract class Entrypoint extends ChunkGroup {
* Fetches the chunk reference containing the webpack bootstrap code
*/
getRuntimeChunk(): Chunk;
/**
* Sets the chunk with the entrypoint modules for an entrypoint.
*/
setEntrypointChunk(chunk: Chunk): void;
/**
* Returns the chunk which contains the entrypoint modules
* (or at least the execution of them)
*/
getEntrypointChunk(): Chunk;
}
declare class EnvironmentPlugin {
constructor(...keys: any[]);