Compilation 钩子
Compilation 钩子
Compilation 模块被 Compiler 用来创建新的编译(或构建)。一个 compilation 实例可以访问所有模块及其依赖(其中大部分是循环引用)。它是对应用程序依赖图中所有模块的实际编译。在编译阶段,模块被加载、封装(sealed)、优化、分块(chunked)、哈希和恢复。
Compilation 类也继承自 Tapable,并提供了以下生命周期钩子。它们可以像 compiler 钩子一样被 tap:
js
compilation.hooks.someHook.tap(/* ... */);
与 compiler 一样,根据钩子的类型,也可能可以使用 tapAsync 和 tapPromise。
W> 自 webpack 5 起,hooks 不再是可扩展的。请使用 WeakMap 来添加自定义钩子。
buildModule
SyncHook
在模块构建开始前触发,可用于修改模块。
- 回调参数:
module
js
compilation.hooks.buildModule.tap(
"SourceMapDevToolModuleOptionsPlugin",
(module) => {
module.useSourceMap = true;
},
);
rebuildModule
SyncHook
在重建模块之前触发。
- 回调参数:
module
failedModule
SyncHook
当模块构建失败时运行。
- 回调参数:
moduleerror
succeedModule
SyncHook
当模块成功构建后执行。
- 回调参数:
module
finishModules
AsyncSeriesHook
当所有模块都无错误地构建完成后调用。
- 回调参数:
modules
finishRebuildingModule
SyncHook
当模块重建后执行,无论成功或出错。
- 回调参数:
module
seal
SyncHook
当编译停止接受新模块时触发。
unseal
SyncHook
当编译开始接受新模块时触发。
optimizeDependencies
SyncBailHook
在依赖优化开始时触发。
- 回调参数:
modules
afterOptimizeDependencies
SyncHook
在依赖优化之后触发。
- 回调参数:
modules
afterChunks
SyncHook
afterChunks 钩子在创建 chunks 和模块图之后、优化它们之前被调用。这个钩子提供了一个检查、分析和必要时修改 chunk 图的机会。
这里有一个示例,展示如何使用 compilation.hooks.afterChunks 钩子。
- 回调参数:
chunks
optimize
SyncHook
在优化阶段开始时触发。
optimizeModules
SyncBailHook
在模块优化阶段开始时调用。插件可以 tap 这个钩子来对模块执行优化。
- 回调参数:
modules
afterOptimizeModules
SyncHook
在模块优化完成后调用。
- 回调参数:
modules
optimizeChunks
SyncBailHook
在 chunk 优化阶段开始时调用。插件可以 tap 这个钩子来对 chunk 执行优化。
- 回调参数:
chunks
afterOptimizeChunks
SyncHook
在 chunk 优化完成后触发。
- 回调参数:
chunks
optimizeTree
AsyncSeriesHook
在优化依赖树之前调用。插件可以 tap 这个钩子来执行依赖树优化。
- 回调参数:
chunksmodules
afterOptimizeTree
SyncHook
在依赖树优化成功完成后调用。
- 回调参数:
chunksmodules
optimizeChunkModules
SyncBailHook
在树优化之后、chunk 模块优化开始时调用。插件可以 tap 这个钩子来执行 chunk 模块的优化。
- 回调参数:
chunksmodules
afterOptimizeChunkModules
SyncHook
在 chunk 模块优化成功完成后调用。
- 回调参数:
chunksmodules
shouldRecord
SyncBailHook
调用以确定是否存储记录。返回任何 !== false 的值将阻止所有其他“记录”钩子被执行(record、recordModules、recordChunks 和 recordHash)。
reviveModules
SyncHook
从记录中恢复模块信息。
- 回调参数:
modulesrecords
beforeModuleIds
SyncHook
在给每个模块分配 id 之前执行。
- 回调参数:
modules
moduleIds
SyncHook
调用以给每个模块分配 id。
- 回调参数:
modules
optimizeModuleIds
SyncHook
在模块 id 优化开始时调用。
- 回调参数:
modules
afterOptimizeModuleIds
SyncHook
当模块 id 优化阶段完成后调用。
- 回调参数:
modules
reviveChunks
SyncHook
从记录中恢复 chunk 信息。
- 回调参数:
chunksrecords
beforeChunkIds
SyncHook
在给每个 chunk 分配 id 之前执行。
- 回调参数:
chunks
chunkIds
SyncHook
调用以给每个 chunk 分配 id。
- 回调参数:
chunks
optimizeChunkIds
SyncHook
在 chunk id 优化阶段开始时调用。
- 回调参数:
chunks
afterOptimizeChunkIds
SyncHook
在 chunk id 优化完成后触发。
- 回调参数:
chunks
recordModules
SyncHook
将模块信息存储到记录中。只有当 shouldRecord 返回真值时才会触发。
- 回调参数:
modulesrecords
recordChunks
SyncHook
将 chunk 信息存储到记录中。仅当 shouldRecord 返回真值时才会触发。
- 回调参数:
chunksrecords
beforeModuleHash
SyncHook
在模块被哈希之前调用。
afterModuleHash
syncHook
在模块被哈希之后调用。
beforeHash
SyncHook
在编译被哈希之前调用。
afterHash
SyncHook
在编译被哈希之后调用。
recordHash
SyncHook
将记录哈希的信息存储到 records 中。仅当 shouldRecord 返回真值时才会触发。
- 回调参数:
records
record
SyncHook
将 compilation 的信息存储到 records 中。仅当 shouldRecord 返回真值时才会触发。
- 回调参数:
compilationrecords
beforeModuleAssets
SyncHook
在创建模块资源之前执行。
additionalChunkAssets
SyncHook
W> additionalChunkAssets 已弃用(请改用 Compilation.hook.processAssets,并使用其中一个 Compilation.PROCESS_ASSETS_STAGE_* 作为 stage 选项)
为 chunk 创建额外的资源。
- 回调参数:
chunks
shouldGenerateChunkAssets
SyncBailHook
调用以确定是否生成 chunk 资源。返回任何 !== false 的值将允许生成 chunk 资源。
beforeChunkAssets
SyncHook
在创建 chunk 资源之前执行。
additionalAssets
AsyncSeriesHook
W> additionalAssets 已弃用(请改用 Compilation.hook.processAssets 钩子,并使用其中一个 Compilation.PROCESS_ASSETS_STAGE_* 作为 stage 选项)
为编译创建额外的资源。这个钩子可以用来例如下载图片:
js
compilation.hooks.additionalAssets.tapAsync("MyPlugin", (callback) => {
download("https://img.shields.io/npm/v/webpack.svg", (resp) => {
if (resp.status === 200) {
compilation.assets["webpack-version.svg"] = toAsset(resp);
callback();
} else {
callback(
new Error("[webpack-example-plugin] Unable to download the image"),
);
}
});
});
optimizeChunkAssets
AsyncSeriesHook
W> optimizeChunkAssets 已弃用(请改用 Compilation.hook.processAssets,并使用其中一个 Compilation.PROCESS_ASSETS_STAGE_* 作为 stage 选项)
优化任何 chunk 资源。资源存储在 compilation.assets 中。一个 Chunk 有一个 files 属性,指向该 chunk 创建的所有文件。任何额外的 chunk 资源存储在 compilation.additionalChunkAssets 中。
- 回调参数:
chunks
下面是一个为每个 chunk 添加横幅(banner)的示例。
js
compilation.hooks.optimizeChunkAssets.tapAsync(
"MyPlugin",
(chunks, callback) => {
for (const chunk of chunks) {
for (const file of chunk.files) {
compilation.assets[file] = new ConcatSource(
"/**Sweet Banner**/",
"\n",
compilation.assets[file],
);
}
}
callback();
},
);
afterOptimizeChunkAssets
SyncHook
W> afterOptimizeChunkAssets 已弃用(请改用 Compilation.hook.processAssets,并使用其中一个 Compilation.PROCESS_ASSETS_STAGE_* 作为 stage 选项)
chunk 资源已经被优化。
- 回调参数:
chunks
下面是一个来自 @boopathi 的示例插件,它输出每个 chunk 中具体包含的内容。
js
compilation.hooks.afterOptimizeChunkAssets.tap("MyPlugin", (chunks) => {
for (const chunk of chunks) {
console.log({
id: chunk.id,
name: chunk.name,
includes: chunk.getModules().map((module) => module.request),
});
}
});
optimizeAssets
AsyncSeriesHook
W> optimizeAssets 已弃用(请改用 Compilation.hook.processAssets 钩子)
优化存储在 compilation.assets 中的所有资源。
- 回调参数:
assets
afterOptimizeAssets
SyncHook
W> afterOptimizeAssets 已弃用(请改用 Compilation.hook.afterProcessAssets 钩子)
资源已经被优化。
- 回调参数:
assets
processAssets
AsyncSeriesHook
资源处理。
钩子参数:
name: string— 插件的名称stage: Stage— 要 tap 的阶段(参见下面的支持的阶段列表)additionalAssets?: true | (assets, [callback]) => (void | Promise<void>)— 用于额外资源的回调(参见下面的额外资源)
回调参数:
assets: { [pathname: string]: Source }— 一个普通对象,其中键是资源的路径名,值是资源的数据,由Source表示。
示例:
js
compilation.hooks.processAssets.tap(
{
name: "MyPlugin",
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, // 更多阶段见下文
},
(assets) => {
console.log("List of assets and their sizes:");
for (const [pathname, source] of Object.entries(assets)) {
console.log(`— ${pathname}: ${source.size()} bytes`);
}
},
);
额外资源
除了 name 和 stage,你还可以传递一个 additionalAssets true 或一个回调函数,该回调函数接收 assets 作为第一个参数:
-
true— 对于插件稍后添加的资源,再次运行提供的回调。在这种模式下,回调将被多次调用:一次用于在指定阶段之前添加的资源,以及多次用于插件稍后(在当前或下一阶段)添加的资源。
jscompilation.hooks.processAssets.tap( { name: "MyPlugin", stage: Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING, additionalAssets: true, }, (assets) => { // 这个函数将被多次调用,每次处理一批资产 }, ); -
(assets, [callback]) => (void | Promise<void>)— 针对插件稍后(在当前或下一阶段)添加的资源运行指定的回调。回调必须与所使用的 tap 方法的类型相匹配(例如,当与tapPromise()一起使用时,它应该返回一个 promise)。jscompilation.hooks.processAssets.tap( { name: "MyPlugin", stage: Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING, additionalAssets: (assets) => { // 这个函数可能会被多次调用,用于处理在后续阶段添加的资源 }, }, (assets) => { // 这个函数将被调用一次,处理插件在先前阶段添加的资源 }, );
资源处理阶段列表
以下是支持的阶段列表(按处理顺序):
PROCESS_ASSETS_STAGE_ADDITIONAL— 向编译添加额外的资源。PROCESS_ASSETS_STAGE_PRE_PROCESS— 资源的基本预处理。PROCESS_ASSETS_STAGE_DERIVED— 从现有资源派生新资源。PROCESS_ASSETS_STAGE_ADDITIONS— 向现有资源添加额外的部分,例如横幅或初始化代码。PROCESS_ASSETS_STAGE_OPTIMIZE— 以一般方式优化现有资源。PROCESS_ASSETS_STAGE_OPTIMIZE_COUNT— 优化现有资源的数量,例如通过合并它们。PROCESS_ASSETS_STAGE_OPTIMIZE_COMPATIBILITY— 优化现有资源的兼容性,例如添加 polyfill 或厂商前缀。PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE— 优化现有资源的大小,例如通过最小化或省略空白。PROCESS_ASSETS_STAGE_DEV_TOOLING— 向资源添加开发工具,例如通过提取 source map。PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE— 优化现有资源的数量,例如通过将资源内联到其他资源中。 PROCESS_ASSETS_STAGE_SUMMARIZE— 汇总现有资源的列表。PROCESS_ASSETS_STAGE_OPTIMIZE_HASH— 优化资源的哈希,例如通过生成资源内容的真实哈希。PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER— 优化现有资源的传输,例如通过准备压缩(gzip)文件作为单独的资源。PROCESS_ASSETS_STAGE_ANALYSE— 分析现有资源。PROCESS_ASSETS_STAGE_REPORT— 为报告目的创建资源。
资源信息
此钩子不会自动提供“资源信息”元数据。如果需要,你将必须使用 compilation 实例和提供的资源路径名手动解析此元数据。这将在未来的 webpack 版本中得到改进。
示例:
js
compilation.hooks.processAssets.tap(
{
/** … */
},
(assets) => {
for (const [pathname, source] of Object.entries(assets)) {
const assetInfo = compilation.assetsInfo.get(pathname);
// @todo: 对 "pathname"、"source" 和 "assetInfo" 做一些处理
}
},
);
afterProcessAssets
SyncHook
在 processAssets 钩子无错误地完成后调用。
needAdditionalSeal
SyncBailHook
调用以确定编译是否需要取消封装以包含其他文件。
afterSeal
AsyncSeriesHook
在 needAdditionalSeal 之后立即执行。
chunkHash
SyncHook
为每个 chunk 触发以生成哈希。
- 回调参数:
chunkchunkHash
moduleAsset
SyncHook
当来自模块的资源被添加到编译时调用。
- 回调参数:
modulefilename
chunkAsset
SyncHook
当来自 chunk 的资源被添加到编译时触发。
- 回调参数:
chunkfilename
assetPath
SyncWaterfallHook
调用以确定资源的路径。
- 回调参数:
pathoptions
needAdditionalPass
SyncBailHook
调用以确定资源在发出后是否需要进一步处理。
childCompiler
SyncHook
在设置子编译器后执行。
- 回调参数:
childCompilercompilerNamecompilerIndex
normalModuleLoader
自 webpack v5 起,normalModuleLoader 钩子已被移除。现在要访问 loader,请使用 NormalModule.getCompilationHooks(compilation).loader。
statsPreset
HookMap
这个 HookMap 类似于一系列动作,当使用预设时会触发。它接收一个 options 对象。当插件管理预设时,它应该小心地修改这个对象中的设置,而不是替换现有的设置。
- 回调参数:
optionscontext
这是一个示例插件:
js
compilation.hooks.statsPreset.for("my-preset").tap("MyPlugin", (options) => {
if (options.all === undefined) options.all = true;
});
这个插件确保对于预设 'my-preset',如果 all 选项未定义,则默认为 true。
statsNormalize
SyncHook
这个钩子用于将 options 对象转换为一致的格式,以便后续钩子可以轻松使用。它还确保缺失的选项被设置为默认值。
- 回调参数:
optionscontext
这是一个示例插件:
js
compilation.hooks.statsNormalize.tap("MyPlugin", (options) => {
if (options.myOption === undefined) options.myOption = [];
if (!Array.isArray(options.myOption)) options.myOptions = [options.myOptions];
});
在这个插件中,如果 myOption 缺失,则将其设置为空数组。此外,它确保 myOption 始终是一个数组,即使它最初被定义为单个值。
statsFactory
这个钩子提供了对特定选项的 StatsFactory 类 的访问。
- 回调参数:
statsFactoryoptions
StatsFactory.hooks.extract
HookMap
- 回调参数:
objectdatacontext
data 包含类。object 是要添加属性的对象。context 提供上下文信息,例如路径上的类。
示例:
js
compilation.hooks.statsFactory.tap("MyPlugin", (statsFactory, options) => {
statsFactory.hooks.extract
.for("compilation")
.tap("MyPlugin", (object, compilation) => {
object.customProperty = MyPlugin.getCustomValue(compilation);
});
});
StatsFactory.hooks.result
HookMap
在每个级别上以结果调用。
- 回调参数:
resultcontext
statsPrinter
这个钩子提供了对特定选项的 StatsPrinter 类 的访问。
- 回调参数:
statsPrinteroptions
StatsPrinter.hooks.print
HookMap
当应打印某个部分时调用此钩子。
- 回调参数:
objectcontext
StatsPrinter.hooks.result
HookMap
当某个部分的结果字符串生成时调用此钩子。
- 回调参数:
resultcontext
CssModulesPlugin.getCompilationHooks(compilation)
当启用 experiments.css 时,内部的 CssModulesPlugin 为插件作者提供了一组每个编译(per-compilation)的钩子。通过静态方法 getCompilationHooks(compilation) 访问它们:
js
const webpack = require("webpack");
class MyCssPlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap("MyCssPlugin", (compilation) => {
const hooks =
webpack.css.CssModulesPlugin.getCompilationHooks(compilation);
// 在这里 tap 钩子
});
}
}
W> 这些钩子仅在启用了 experiments.css 时注册,并且可能在 CSS 功能处于实验阶段时发生变化。
orderModules
SyncBailHook<[Chunk, Module[], Compilation], Module[] | undefined>
对于每种 CSS 源类型(CSS 导入和 CSS 模块),使用按完整模块名预排序的 chunk 模块调用一次。Tap 可以返回一个有序的 Module[] 来覆盖 webpack 默认的导入顺序拓扑排序,或者返回 undefined 以保持默认顺序。
当 webpack 的拓扑排序暴露出无法通过重构导入来解决的 Conflicting order between css ... 警告时,此钩子是推荐的逃生舱口(escape hatch)。返回预排序的数组(或任何确定性顺序)可以让构建选择稳定的顺序,而无需更改应用程序代码。
- 回调参数:
chunkmodulescompilation
js
const webpack = require("webpack");
class CssOrderByPathPlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap(
"CssOrderByPathPlugin",
(compilation) => {
const hooks =
webpack.css.CssModulesPlugin.getCompilationHooks(compilation);
// 模块到达时已按完整模块名预排序;原样返回以
// 在重建时强制执行确定性的文件路径顺序,并
// 避免冲突顺序警告。
hooks.orderModules.tap(
"CssOrderByPathPlugin",
(_chunk, modules) => modules,
);
},
);
}
}
该钩子是一个 SyncBailHook,因此第一个返回非 undefined 值的 tap 生效。对于该调用,后续的 tap 将不会被调用。
HtmlModulesPlugin.getCompilationHooks(compilation)
当启用 experiments.html 时,内部的 HtmlModulesPlugin 为插件作者提供了一组每个编译(per-compilation)的钩子,用于注入和转换生成的 HTML 页面。通过静态方法 getCompilationHooks(compilation) 访问它们:
js
const webpack = require("webpack");
class MyHtmlPlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap("MyHtmlPlugin", (compilation) => {
const hooks =
webpack.html.HtmlModulesPlugin.getCompilationHooks(compilation);
// 在这里 tap 钩子
});
}
}
W> 这些钩子仅在启用了 experiments.html 时注册,并且可能在 HTML 功能处于实验阶段时发生变化。
injectTags
AsyncSeriesWaterfallHook<[HtmlTagDescriptor[], { outputName, html }]>
使用要注入到每个页面中的额外标签列表(最初为空)以及当前的 HTML 调用。推送描述符并返回列表;webpack 会序列化并放置它们。它在 output.html.csp 之前运行,因此注入的内联 <script> / <style> 标签会像页面自身的标签一样被哈希。
每个 HtmlTagDescriptor 接受:
tag(string):标签名,例如'script'/'link'/'meta'。attrs(object):属性;true渲染一个裸布尔属性,false/undefined省略它。children(string):内部内容(对于<link>/<meta>等空元素会被忽略)。injectTo('head' | 'body' | 'head-prepend' | 'body-prepend'):放置位置,默认为'head'。voidTag(boolean):强制一个空元素(没有结束标签);省略时从标签名推断。
js
hooks.injectTags.tap("MyHtmlPlugin", (tags) => {
tags.push({
tag: "meta",
attrs: { name: "theme-color", content: "#2b3a42" },
});
return tags;
});
transformTags
AsyncSeriesHook<[HtmlMutableTag[], { outputName, html }]>
使用页面现有的 <script> / <link> / <style> / <meta> 标签(包括 webpack 自身的和任何注入的)作为可变描述符调用。修改 attrs(添加 nonce / data-* 属性,切换 defer 和 async,...),设置 remove: true,或更改 injectTo 以在 <head> 和 <body> 之间移动标签;webpack 会重写更改后的标签。改用 injectTags 添加新标签,并且不要重新排列数组本身。
transformHtml
AsyncSeriesWaterfallHook<[string, { outputName: string }]>
使用每个生成的页面的最终 HTML(所有占位符都已解析)在写入之前调用。返回(可能已转换的)HTML,例如对其进行压缩:
js
hooks.transformHtml.tapPromise("MyHtmlPlugin", async (html, { outputName }) =>
html.replace("<!-- banner -->", "..."),
);
htmlEmitted
AsyncSeriesHook<[{ outputName: string }]>
在每个页面的 HTML 资产最终确定后调用一次 — 一个发出后的通知。
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
