这一节中主要对编译器新建时的执行流程做了一些,对构子部分的汪册以及对资源的处理。
js
constructor(compiler, params) {
// 兼容模式的标志,继承自 compiler
this._backCompat = compiler._backCompat;
// 获取 NormalModuleLoader(已废弃)
const getNormalModuleLoader = () => deprecatedNormalModuleLoaderHook(this);
/**
* @typedef {{ additionalAssets?: true | Function }} ProcessAssetsAdditionalOptions
* 这里定义了 `processAssetsHook` 可能使用的额外选项:
* - `additionalAssets` 可选,值可以是 `true` 或一个函数:
* - `true`:表示所有资产都需要额外处理
* - `Function`:自定义的额外处理逻辑
*/
/**
* 这里定义了一个异步的 `processAssetsHook` 钩子,
* 它是 AsyncSeriesHook(异步串行钩子),用于处理 `assets` 资源
*/
const processAssetsHook = new AsyncSeriesHook(["assets"]);
// 用于存储已经处理过的 `assets` 文件
let savedAssets = new Set();
/**
* @param {CompilationAssets} assets 现有的 `assets` 资源
* @returns {CompilationAssets} 返回新增加的 `assets` 资源
*
* 这个函数的作用是找出 `assets` 中新增的资源,
* 避免重复处理已经存在的资源,并返回新资产的对象。
*/
const popNewAssets = assets => {
let newAssets;
for (const file of Object.keys(assets)) {
// 如果该资源已经存在于 `savedAssets`,则跳过
if (savedAssets.has(file)) continue;
// 初始化 `newAssets` 为空对象
if (newAssets === undefined) {
newAssets = Object.create(null);
}
// 记录新增资源
newAssets[file] = assets[file];
// 将该资源加入 `savedAssets`
savedAssets.add(file);
}
return newAssets;
};
// 拦截 `processAssetsHook` 的调用过程
processAssetsHook.intercept({
name: "Compilation",
// 在 `call` 事件发生时,记录当前 `assets` 的状态
call: () => {
savedAssets = new Set(Object.keys(this.assets));
},
// 拦截 `register` 事件,修改注册的 `tap` 函数
register: tap => {
const { type, name } = tap;
const { fn, additionalAssets, ...remainingTap } = tap;
// 处理 `additionalAssets` 选项:
// 如果是 `true`,使用原 `fn` 作为 `additionalAssetsFn`
// 如果是函数,则直接使用该函数
const additionalAssetsFn =
additionalAssets === true ? fn : additionalAssets;
// 记录已处理的 `assets`,防止重复处理
const processedAssets = additionalAssetsFn ? new WeakSet() : undefined;
// 根据 `type` 处理不同类型的 `tap`
switch (type) {
case "sync": // 同步钩子
if (additionalAssetsFn) {
// 注册 `processAdditionalAssets` 钩子
this.hooks.processAdditionalAssets.tap(name, assets => {
if (processedAssets.has(this.assets)) {
additionalAssetsFn(assets);
}
});
}
// 将 `sync` 方式转换为 `async`
return {
...remainingTap,
type: "async",
fn: (assets, callback) => {
try {
fn(assets);
} catch (err) {
return callback(err);
}
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
this.hooks.processAdditionalAssets.callAsync(
newAssets,
callback
);
return;
}
callback();
}
};
case "async": // 异步钩子
if (additionalAssetsFn) {
// 注册 `processAdditionalAssets` 异步钩子
this.hooks.processAdditionalAssets.tapAsync(
name,
(assets, callback) => {
if (processedAssets.has(this.assets))
return additionalAssetsFn(assets, callback);
callback();
}
);
}
return {
...remainingTap,
fn: (assets, callback) => {
fn(assets, err => {
if (err) return callback(err);
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
this.hooks.processAdditionalAssets.callAsync(
newAssets,
callback
);
return;
}
callback();
});
}
};
case "promise": // Promise 方式的钩子
if (additionalAssetsFn) {
// 注册 `processAdditionalAssets` 的 Promise 钩子
this.hooks.processAdditionalAssets.tapPromise(name, assets => {
if (processedAssets.has(this.assets))
return additionalAssetsFn(assets);
return Promise.resolve();
});
}
return {
...remainingTap,
fn: assets => {
const p = fn(assets);
if (!p || !p.then) return p;
return p.then(() => {
if (processedAssets !== undefined)
processedAssets.add(this.assets);
const newAssets = popNewAssets(assets);
if (newAssets !== undefined) {
return this.hooks.processAdditionalAssets.promise(
newAssets
);
}
});
}
};
}
}
});
/**
* @type {SyncHook<[CompilationAssets]>}
* 定义一个同步钩子 `afterProcessAssetsHook`,用于在 `processAssetsHook` 之后执行额外的操作
*/
const afterProcessAssetsHook = new SyncHook(["assets"]);
/**
* @template T
* @param {string} name hook 的名称
* @param {number} stage 该 hook 在 processAssetsHook 执行的阶段
* @param {function(): AsArray<T>} getArgs 获取旧 hook 需要的参数
* @param {string=} code 废弃代码的标识(如果未设置,则不认为是废弃)
* @returns {FakeHook<Pick<AsyncSeriesHook<T>, "tap" | "tapAsync" | "tapPromise" | "name">>}
* 返回一个模拟的 `hook`,用于将老的 `hook` 重定向到 `processAssetsHook`
*
* 这个方法用于创建一个"虚拟的" `processAssetsHook`,使得旧的钩子 API 仍然可以使用,
* 但实际上它们会被引导到 `processAssetsHook`,以保持 Webpack 5 兼容 Webpack 4。
*/
const createProcessAssetsHook = (name, stage, getArgs, code) => {
// 如果不在兼容模式下,并且 `code` 存在(表示该 API 被废弃),则直接返回,不创建 hook
if (!this._backCompat && code) return;
/**
* 生成错误信息的函数
* @param {string} reason 失败的原因
* @returns {string} 返回错误信息
*
* 这个函数用于提示用户,Webpack 5 统一了 `processAssets` 相关的 hooks,导致旧的 hooks 不能直接使用。
*/
const errorMessage =
reason => `Can't automatically convert plugin using Compilation.hooks.${name} to Compilation.hooks.processAssets because ${reason}.
BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a single Compilation.hooks.processAssets hook.`;
/**
* 解析 `options` 并附加 `stage` 参数
* @param {Object|string} options 传入的 tap 选项,可以是字符串或对象
* @returns {Object} 返回带 `stage` 选项的新对象
*
* 这个函数的作用是确保 `options` 格式正确,并且禁止用户手动指定 `stage`,
* 因为 `stage` 由 `createProcessAssetsHook` 统一管理。
*/
const getOptions = options => {
if (typeof options === "string") options = { name: options };
if (options.stage) {
// 如果用户尝试指定 `stage`,则抛出错误
throw new Error(errorMessage("it's using the 'stage' option"));
}
return { ...options, stage };
};
// 创建一个模拟的 `hook`,用于兼容 Webpack 4 的老 API
return createFakeHook(
{
name,
/**
* @type {AsyncSeriesHook<T>["intercept"]}
* 拦截 `intercept` 方法,直接抛出错误,提示用户该 API 不能被拦截。
*/
intercept(interceptor) {
throw new Error(errorMessage("it's using 'intercept'"));
},
/**
* @type {AsyncSeriesHook<T>["tap"]}
* 处理 `tap` 方法,将其重定向到 `processAssetsHook.tap`
*/
tap: (options, fn) => {
processAssetsHook.tap(getOptions(options), () => fn(...getArgs()));
},
/**
* @type {AsyncSeriesHook<T>["tapAsync"]}
* 处理 `tapAsync` 方法,将其重定向到 `processAssetsHook.tapAsync`
*/
tapAsync: (options, fn) => {
processAssetsHook.tapAsync(
getOptions(options),
(assets, callback) =>
/** @type {any} */(fn)(...getArgs(), callback)
);
},
/**
* @type {AsyncSeriesHook<T>["tapPromise"]}
* 处理 `tapPromise` 方法,将其重定向到 `processAssetsHook.tapPromise`
*/
tapPromise: (options, fn) => {
processAssetsHook.tapPromise(getOptions(options), () =>
fn(...getArgs())
);
}
},
// 提示用户,该 `hook` 已被废弃,建议使用 `processAssetsHook` 并指定 `stage`
`${name} is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)`,
code
);
};
this.hooks = Object.freeze({
/** @type {SyncHook<[Module]>} */
buildModule: new SyncHook(["module"]), // 构建模块的钩子
/** @type {SyncHook<[Module]>} */
rebuildModule: new SyncHook(["module"]), // 重新构建模块的钩子
/** @type {SyncHook<[Module, WebpackError]>} */
failedModule: new SyncHook(["module", "error"]), // 模块构建失败的钩子
/** @type {SyncHook<[Module]>} */
succeedModule: new SyncHook(["module"]), // 模块构建成功的钩子
/** @type {SyncHook<[Module]>} */
stillValidModule: new SyncHook(["module"]), // 模块仍然有效的钩子
/** @type {SyncHook<[Dependency, EntryOptions]>} */
addEntry: new SyncHook(["entry", "options"]), // 添加入口的钩子
/** @type {SyncHook<[Dependency, EntryOptions, Error]>} */
failedEntry: new SyncHook(["entry", "options", "error"]), // 入口添加失败的钩子
/** @type {SyncHook<[Dependency, EntryOptions, Module]>} */
succeedEntry: new SyncHook(["entry", "options", "module"]), // 入口添加成功的钩子
/** @type {SyncWaterfallHook<[(string[] | ReferencedExport)[], Dependency, RuntimeSpec]>} */
dependencyReferencedExports: new SyncWaterfallHook([
"referencedExports", "dependency", "runtime"
]), // 依赖项引用导出的钩子
/** @type {SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
executeModule: new SyncHook(["options", "context"]), // 执行模块的钩子
/** @type {AsyncParallelHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */
prepareModuleExecution: new AsyncParallelHook(["options", "context"]), // 准备执行模块的钩子
/** @type {AsyncSeriesHook<[Iterable<Module>]>} */
finishModules: new AsyncSeriesHook(["modules"]), // 完成模块处理的钩子
/** @type {AsyncSeriesHook<[Module]>} */
finishRebuildingModule: new AsyncSeriesHook(["module"]), // 完成重新构建模块的钩子
/** @type {SyncHook<[]>} */
unseal: new SyncHook([]), // 解封的钩子
/** @type {SyncHook<[]>} */
seal: new SyncHook([]), // 密封的钩子
/** @type {SyncHook<[]>} */
beforeChunks: new SyncHook([]), // 在分块之前的钩子
/** @type {SyncHook<[Iterable<Chunk>]>} */
afterChunks: new SyncHook(["chunks"]), // 在分块之后的钩子
/** @type {SyncBailHook<[Iterable<Module>], boolean | void>} */
optimizeDependencies: new SyncBailHook(["modules"]), // 优化依赖项的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
afterOptimizeDependencies: new SyncHook(["modules"]), // 优化依赖项后的钩子
/** @type {SyncHook<[]>} */
optimize: new SyncHook([]), // 优化的钩子
/** @type {SyncBailHook<[Iterable<Module>], boolean | void>} */
optimizeModules: new SyncBailHook(["modules"]), // 优化模块的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
afterOptimizeModules: new SyncHook(["modules"]), // 优化模块后的钩子
/** @type {SyncBailHook<[Iterable<Chunk>, ChunkGroup[]], boolean | void>} */
optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]), // 优化分块的钩子
/** @type {SyncHook<[Iterable<Chunk>, ChunkGroup[]]>} */
afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]), // 优化分块后的钩子
/** @type {AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>} */
optimizeTree: new AsyncSeriesHook(["chunks", "modules"]), // 优化树形结构的钩子
/** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
afterOptimizeTree: new SyncHook(["chunks", "modules"]), // 优化树形结构后的钩子
/** @type {AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>], void>} */
optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]), // 优化分块模块的钩子
/** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]), // 优化分块模块后的钩子
/** @type {SyncBailHook<[], boolean | void>} */
shouldRecord: new SyncBailHook([]), // 是否需要记录的钩子
/** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
additionalChunkRuntimeRequirements: new SyncHook([
"chunk", "runtimeRequirements", "context"
]), // 额外分块的运行时需求的钩子
/** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext], void>>} */
runtimeRequirementInChunk: new HookMap(
() => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
), // 在分块中运行时需求的钩子
/** @type {SyncHook<[Module, Set<string>, RuntimeRequirementsContext]>} */
additionalModuleRuntimeRequirements: new SyncHook([
"module", "runtimeRequirements", "context"
]), // 额外模块的运行时需求的钩子
/** @type {HookMap<SyncBailHook<[Module, Set<string>, RuntimeRequirementsContext], void>>} */
runtimeRequirementInModule: new HookMap(
() => new SyncBailHook(["module", "runtimeRequirements", "context"])
), // 在模块中运行时需求的钩子
/** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
additionalTreeRuntimeRequirements: new SyncHook([
"chunk", "runtimeRequirements", "context"
]), // 额外树形结构的运行时需求的钩子
/** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext], void>>} */
runtimeRequirementInTree: new HookMap(
() => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
), // 在树形结构中运行时需求的钩子
/** @type {SyncHook<[RuntimeModule, Chunk]>} */
runtimeModule: new SyncHook(["module", "chunk"]), // 运行时模块的钩子
/** @type {SyncHook<[Iterable<Module>, any]>} */
reviveModules: new SyncHook(["modules", "records"]), // 恢复模块的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
beforeModuleIds: new SyncHook(["modules"]), // 在模块ID之前的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
moduleIds: new SyncHook(["modules"]), // 模块ID的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
optimizeModuleIds: new SyncHook(["modules"]), // 优化模块ID的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
afterOptimizeModuleIds: new SyncHook(["modules"]), // 优化模块ID后的钩子
/** @type {SyncHook<[Iterable<Chunk>, any]>} */
reviveChunks: new SyncHook(["chunks", "records"]), // 恢复分块的钩子
/** @type {SyncHook<[Iterable<Chunk>]>} */
beforeChunkIds: new SyncHook(["chunks"]), // 在分块ID之前的钩子
/** @type {SyncHook<[Iterable<Chunk>]>} */
chunkIds: new SyncHook(["chunks"]), // 分块ID的钩子
/** @type {SyncHook<[Iterable<Chunk>]>} */
optimizeChunkIds: new SyncHook(["chunks"]), // 优化分块ID的钩子
/** @type {SyncHook<[Iterable<Chunk>]>} */
afterOptimizeChunkIds: new SyncHook(["chunks"]), // 优化分块ID后的钩子
/** @type {SyncHook<[Iterable<Module>, any]>} */
recordModules: new SyncHook(["modules", "records"]), // 记录模块的钩子
/** @type {SyncHook<[Iterable<Chunk>, any]>} */
recordChunks: new SyncHook(["chunks", "records"]), // 记录分块的钩子
/** @type {SyncHook<[Iterable<Module>]>} */
optimizeCodeGeneration: new SyncHook(["modules"]), // 优化代码生成的钩子
/** @type {SyncHook<[]>} */
beforeModuleHash: new SyncHook([]), // 在模块哈希之前的钩子
/** @type {SyncHook<[]>} */
afterModuleHash: new SyncHook([]), // 模块哈希之后的钩子
/** @type {SyncHook<[]>} */
beforeCodeGeneration: new SyncHook([]), // 在代码生成之前的钩子
/** @type {SyncHook<[]>} */
afterCodeGeneration: new SyncHook([]), // 代码生成之后的钩子
/** @type {SyncHook<[]>} */
beforeRuntimeRequirements: new SyncHook([]), // 在运行时需求之前的钩子
/** @type {SyncHook<[]>} */
afterRuntimeRequirements: new SyncHook([]), // 运行时需求之后的钩子
/** @type {SyncHook<[]>} */
beforeHash: new SyncHook([]), // 在哈希之前的钩子
/** @type {SyncHook<[Chunk]>} */
contentHash: new SyncHook(["chunk"]), // 内容哈希的钩子
/** @type {SyncHook<[]>} */
afterHash: new SyncHook([]), // 哈希之后的钩子
/** @type {SyncHook<[any]>} */
recordHash: new SyncHook(["records"]), // 记录哈希的钩子
/** @type {SyncHook<[Compilation, any]>} */
record: new SyncHook(["compilation", "records"]), // 记录的钩子
/** @type {SyncHook<[]>} */
beforeModuleAssets: new SyncHook([]), // 在模块资产之前的钩子
/** @type {SyncBailHook<[], boolean | void>} */
shouldGenerateChunkAssets: new SyncBailHook([]), // 是否需要生成分块资产的钩子
/** @type {SyncHook<[]>} */
beforeChunkAssets: new SyncHook([]), // 在分块资产之前的钩子
/** @deprecated */
additionalChunkAssets: createProcessAssetsHook(
"additionalChunkAssets",
Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
() => [this.chunks],
"DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS"
), // 额外分块资产的钩子(废弃)
/** @deprecated */
additionalAssets: createProcessAssetsHook(
"additionalAssets",
Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
() => []
), // 额外资产的钩子(废弃)
/** @deprecated */
optimizeChunkAssets: createProcessAssetsHook(
"optimizeChunkAssets",
Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,
() => [this.chunks],
"DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS"
), // 优化分块资产的钩子(废弃)
/** @deprecated */
afterOptimizeChunkAssets: createProcessAssetsHook(
"afterOptimizeChunkAssets",
Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1,
() => [this.chunks],
"DEP_WEBPACK_COMPILATION_AFTER_OPTIMIZE_CHUNK_ASSETS"
), // 优化分块资产后的钩子(废弃)
/** @deprecated */
optimizeAssets: processAssetsHook, // 优化资产的钩子(废弃)
/** @deprecated */
afterOptimizeAssets: afterProcessAssetsHook, // 优化资产后的钩子(废弃)
processAssets: processAssetsHook, // 处理资产的钩子
afterProcessAssets: afterProcessAssetsHook, // 处理资产后的钩子
/** @type {AsyncSeriesHook<[CompilationAssets]>} */
processAdditionalAssets: new AsyncSeriesHook(["assets"]), // 处理额外资产的钩子
/** @type {SyncBailHook<[], boolean | void>} */
needAdditionalSeal: new SyncBailHook([]), // 是否需要额外密封的钩子
/** @type {AsyncSeriesHook<[]>} */
afterSeal: new AsyncSeriesHook([]), // 密封之后的钩子
/** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */
renderManifest: new SyncWaterfallHook(["result", "options"]), // 渲染清单的钩子
/** @type {SyncHook<[Hash]>} */
fullHash: new SyncHook(["hash"]), // 完整哈希的钩子
/** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */
chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]), // 分块哈希的钩子
/** @type {SyncHook<[Module, string]>} */
moduleAsset: new SyncHook(["module", "filename"]), // 模块资产的钩子
/** @type {SyncHook<[Chunk, string]>} */
chunkAsset: new SyncHook(["chunk", "filename"]), // 分块资产的钩子
/** @type {SyncWaterfallHook<[string, object, AssetInfo | undefined]>} */
assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]), // 资产路径的钩子
/** @type {SyncBailHook<[], boolean | void>} */
needAdditionalPass: new SyncBailHook([]), // 是否需要额外通道的钩子
/** @type {SyncHook<[Compiler, string, number]>} */
childCompiler: new SyncHook([
"childCompiler", "compilerName", "compilerIndex"
]), // 子编译器的钩子
/** @type {SyncBailHook<[string, LogEntry], boolean | void>} */
log: new SyncBailHook(["origin", "logEntry"]), // 日志钩子
/** @type {SyncWaterfallHook<[WebpackError[]]>} */
processWarnings: new SyncWaterfallHook(["warnings"]), // 处理警告的钩子
/** @type {SyncWaterfallHook<[WebpackError[]]>} */
processErrors: new SyncWaterfallHook(["errors"]), // 处理错误的钩子
/** @type {HookMap<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>} */
statsPreset: new HookMap(() => new SyncHook(["options", "context"])), // 统计预设的钩子
/** @type {SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>} */
statsNormalize: new SyncHook(["options", "context"]), // 统计规范化的钩子
/** @type {SyncHook<[StatsFactory, NormalizedStatsOptions]>} */
statsFactory: new SyncHook(["statsFactory", "options"]), // 统计工厂的钩子
/** @type {SyncHook<[StatsPrinter, NormalizedStatsOptions]>} */
statsPrinter: new SyncHook(["statsPrinter", "options"]), // 统计打印的钩子
// 获取正常模块加载器
get normalModuleLoader() {
return getNormalModuleLoader();
}
});
/** @type {string=} */
this.name = undefined; // 编译的名称,默认为未定义
/** @type {number | undefined} */
this.startTime = undefined; // 编译开始时间,默认为未定义
/** @type {number | undefined} */
this.endTime = undefined; // 编译结束时间,默认为未定义
/** @type {Compiler} */
this.compiler = compiler; // 当前的编译器实例
this.resolverFactory = compiler.resolverFactory; // 用于解析模块的工厂方法
/** @type {InputFileSystem} */
this.inputFileSystem = (compiler.inputFileSystem); // 文件系统接口,用于读取文件
this.fileSystemInfo = new FileSystemInfo(this.inputFileSystem, {
unmanagedPaths: compiler.unmanagedPaths, // 未管理的路径
managedPaths: compiler.managedPaths, // 已管理的路径
immutablePaths: compiler.immutablePaths, // 不可变的路径
logger: this.getLogger("webpack.FileSystemInfo"), // 日志记录器
hashFunction: compiler.options.output.hashFunction // 哈希函数,用于生成文件的哈希值
});
// 添加文件时间戳信息
if (compiler.fileTimestamps) {
this.fileSystemInfo.addFileTimestamps(compiler.fileTimestamps, true);
}
if (compiler.contextTimestamps) {
this.fileSystemInfo.addContextTimestamps(compiler.contextTimestamps, true);
}
/** @type {ValueCacheVersions} */
this.valueCacheVersions = new Map(); // 存储缓存的版本信息
this.requestShortener = compiler.requestShortener; // 请求路径缩短器,用于简化路径显示
this.compilerPath = compiler.compilerPath; // 编译器路径,用于路径解析
this.logger = this.getLogger("webpack.Compilation"); // 编译过程的日志记录器
const options = /** @type {WebpackOptions} */ (compiler.options);
this.options = options; // 配置项
this.outputOptions = options && options.output; // 输出配置项
/** @type {boolean} */
this.bail = (options && options.bail) || false; // 是否在遇到错误时中止编译
/** @type {boolean} */
this.profile = (options && options.profile) || false; // 是否启用性能分析
this.params = params; // 传递的参数
this.mainTemplate = new MainTemplate(this.outputOptions, this); // 主模板,用于生成输出文件
this.chunkTemplate = new ChunkTemplate(this.outputOptions, this); // Chunk模板,用于生成模块拆分后的文件
this.runtimeTemplate = new RuntimeTemplate(this, this.outputOptions, this.requestShortener); // 运行时模板,用于生成运行时代码
/** @type {ModuleTemplates} */
this.moduleTemplates = {
javascript: new ModuleTemplate(this.runtimeTemplate, this) // JavaScript模块模板
};
defineRemovedModuleTemplates(this.moduleTemplates); // 定义已移除的模块模板
/** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */
this.moduleMemCaches = undefined; // 模块内存缓存,用于缓存模块状态
/** @type {Map<Module, WeakTupleMap<any, any>> | undefined} */
this.moduleMemCaches2 = undefined; // 第二级模块内存缓存
this.moduleGraph = new ModuleGraph(); // 模块图,用于追踪模块之间的依赖关系
/** @type {ChunkGraph} */
this.chunkGraph = undefined; // 块图,用于管理生成的块的关系
/** @type {CodeGenerationResults} */
this.codeGenerationResults = undefined; // 代码生成的结果
/** @type {AsyncQueue<Module, Module, Module>} */
this.processDependenciesQueue = new AsyncQueue({
name: "processDependencies", // 队列名称
parallelism: options.parallelism || 100, // 并行度
processor: this._processModuleDependencies.bind(this) // 处理依赖的回调函数
});
/** @type {AsyncQueue<Module, string, Module>} */
this.addModuleQueue = new AsyncQueue({
name: "addModule", // 队列名称
parent: this.processDependenciesQueue, // 父队列
getKey: module => module.identifier(), // 获取模块的唯一标识符
processor: this._addModule.bind(this) // 添加模块的回调函数
});
/** @type {AsyncQueue<FactorizeModuleOptions, string, Module | ModuleFactoryResult>} */
this.factorizeQueue = new AsyncQueue({
name: "factorize", // 队列名称
parent: this.addModuleQueue, // 父队列
processor: this._factorizeModule.bind(this) // 模块因式分解的回调函数
});
/** @type {AsyncQueue<Module, Module, Module>} */
this.buildQueue = new AsyncQueue({
name: "build", // 队列名称
parent: this.factorizeQueue, // 父队列
processor: this._buildModule.bind(this) // 构建模块的回调函数
});
/** @type {AsyncQueue<Module, Module, Module>} */
this.rebuildQueue = new AsyncQueue({
name: "rebuild", // 队列名称
parallelism: options.parallelism || 100, // 并行度
processor: this._rebuildModule.bind(this) // 重新构建模块的回调函数
});
/**
* 当前模块的值为正在构建的模块,表示这些模块正在阻塞其他模块的构建
* 用于检测构建中的循环依赖
* @type {WeakMap<Module, Set<Module>>}
*/
this.creatingModuleDuringBuild = new WeakMap(); // 记录构建中的模块依赖关系
/** @type {Map<string, EntryData>} */
this.entries = new Map(); // 存储入口配置
/** @type {EntryData} */
this.globalEntry = {
dependencies: [], // 入口的依赖
includeDependencies: [], // 包含的依赖
options: {
name: undefined // 入口名称
}
};
/** @type {Map<string, Entrypoint>} */
this.entrypoints = new Map(); // 存储入口点的映射,每个入口点对应一个模块的集合
/** @type {Entrypoint[]} */
this.asyncEntrypoints = []; // 异步入口点的数组,用于处理按需加载的模块
/** @type {Set<Chunk>} */
this.chunks = new Set(); // 存储生成的所有块(Chunk)
/** @type {ChunkGroup[]} */
this.chunkGroups = []; // 存储块组的数组,用于组织多个块的关系
/** @type {Map<string, ChunkGroup>} */
this.namedChunkGroups = new Map(); // 存储命名的块组
/** @type {Map<string, Chunk>} */
this.namedChunks = new Map(); // 存储命名的块
/** @type {Set<Module>} */
this.modules = new Set(); // 存储所有模块的集合
// 兼容旧版本的处理
if (this._backCompat) {
arrayToSetDeprecation(this.chunks, "Compilation.chunks");
arrayToSetDeprecation(this.modules, "Compilation.modules");
}
/**
* @private
* @type {Map<string, Module>}
*/
this._modules = new Map(); // 存储模块的私有映射
this.records = null; // 编译记录,可能用于缓存或保存编译信息
/** @type {string[]} */
this.additionalChunkAssets = []; // 存储额外的块资产
/** @type {CompilationAssets} */
this.assets = {}; // 存储编译生成的资源文件
/** @type {Map<string, AssetInfo>} */
this.assetsInfo = new Map(); // 存储资产信息(如资源的哈希、大小等)
/** @type {Map<string, Map<string, Set<string>>>} */
this._assetsRelatedIn = new Map(); // 存储与资产相关联的映射,用于处理依赖关系
/** @type {WebpackError[]} */
this.errors = []; // 存储编译时的错误信息
/** @type {WebpackError[]} */
this.warnings = []; // 存储编译时的警告信息
/** @type {Compilation[]} */
this.children = []; // 存储子编译实例,用于支持多目标编译
/** @type {Map<string, LogEntry[]>} */
this.logging = new Map(); // 存储日志条目的映射
/** @type {Map<DepConstructor, ModuleFactory>} */
this.dependencyFactories = new Map(); // 存储依赖构造函数和模块工厂的映射,用于处理模块依赖
/** @type {DependencyTemplates} */
this.dependencyTemplates = new DependencyTemplates(this.outputOptions.hashFunction); // 依赖模板,用于生成依赖模块的代码
/** @type {Record<string, number>} */
this.childrenCounters = {}; // 存储子编译实例的计数器,用于支持多目标编译
/** @type {Set<number|string>} */
this.usedChunkIds = null; // 存储已使用的块ID
/** @type {Set<number>} */
this.usedModuleIds = null; // 存储已使用的模块ID
/** @type {boolean} */
this.needAdditionalPass = false; // 是否需要额外的编译遍历
/** @type {Set<Module & { restoreFromUnsafeCache: Function }>} */
this._restoredUnsafeCacheModuleEntries = new Set(); // 存储恢复自不安全缓存的模块条目
/** @type {Map<string, Module & { restoreFromUnsafeCache: Function }>} */
this._restoredUnsafeCacheEntries = new Map(); // 存储恢复自不安全缓存的模块条目映射
/** @type {WeakSet<Module>} */
this.builtModules = new WeakSet(); // 存储已构建的模块,用于避免重复构建
/** @type {WeakSet<Module>} */
this.codeGeneratedModules = new WeakSet(); // 存储已生成代码的模块,用于标记已处理的模块
/** @type {WeakSet<Module>} */
this.buildTimeExecutedModules = new WeakSet(); // 存储在构建期间执行过的模块
/** @type {Set<string>} */
this.emittedAssets = new Set(); // 存储已发出的资产,用于追踪已输出的资源文件
/** @type {Set<string>} */
this.comparedForEmitAssets = new Set(); // 存储已比较的资产,用于避免重复发出
/** @type {LazySet<string>} */
this.fileDependencies = new LazySet(); // 存储文件依赖,懒加载集合
/** @type {LazySet<string>} */
this.contextDependencies = new LazySet(); // 存储上下文依赖,懒加载集合
/** @type {LazySet<string>} */
this.missingDependencies = new LazySet(); // 存储缺失的依赖,懒加载集合
/** @type {LazySet<string>} */
this.buildDependencies = new LazySet(); // 存储构建时的依赖,懒加载集合
// TODO webpack 6 删除,旧版本兼容
this.compilationDependencies = {
add: util.deprecate(
/**
* @param {string} item item
* @returns {LazySet<string>} file dependencies
*/
item => this.fileDependencies.add(item),
"Compilation.compilationDependencies is deprecated (used Compilation.fileDependencies instead)",
"DEP_WEBPACK_COMPILATION_COMPILATION_DEPENDENCIES"
)
};
// 使用缓存来存储模块、资产和代码生成的状态
this._modulesCache = this.getCache("Compilation/modules");
this._assetsCache = this.getCache("Compilation/assets");
this._codeGenerationCache = this.getCache("Compilation/codeGeneration");
const unsafeCache = options.module.unsafeCache;
this._unsafeCache = Boolean(unsafeCache); // 是否启用不安全缓存
this._unsafeCachePredicate = typeof unsafeCache === "function" ? unsafeCache : () => true; // 不安全缓存的判定函数
}