Webpack自定义Plugin的核心是通过监听compiler和compilation的钩子介入构建流程:compiler代表全局构建环境,适合run、done等全局事件;compilation代表单次构建实例,适合操作assets、chunks等资源。

Webpack 自定义 Plugin 的核心是通过监听编译生命周期中的钩子(Hooks)来介入构建流程。Plugin 本质是一个带有 apply 方法的对象,Webpack 在编译不同阶段会调用注册的钩子回调,你只需在 apply 中使用 compiler.hooks.xxx.tap 或 compilation.hooks.xxx.tap 绑定逻辑即可。
理解 compiler 和 compilation 两个关键对象
compiler 是 Webpack 启动时创建的全局实例,代表整个构建环境,生命周期长(一次构建只一个),适合监听全局事件如 run、done、emit。
compilation 是每次构建(含增量构建)生成的实例,包含当前构建的所有资源、模块、依赖等信息,生命周期短,适合操作资源、修改 assets、处理 chunk 等。
- 在
compiler.hooks.run.tap中可做构建前初始化(如清空目录、读取配置) - 在
compilation.hooks.seal.tap中可访问已生成但未输出的 chunk 和 modules - 在
compilation.hooks.processAssets.tap中可读写最终输出的 assets(推荐用Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL等阶段常量控制时机)
编写一个基础 Plugin 示例:注入构建时间到 HTML
假设你想在每个 HTML 输出文件开头插入一行构建时间,可用 compilation.hooks.processAssets 钩子:
class InjectBuildTimePlugin {
apply(compiler) {
compiler.hooks.thisCompilation.tap('InjectBuildTimePlugin', (compilation) => {
compilation.hooks.processAssets.tap(
{
name: 'InjectBuildTimePlugin',
stage: compilation.constructor.PROCESS_ASSETS_STAGE_ADDITIONAL
},
() => {
for (const filename of Object.keys(compilation.assets)) {
if (filename.endsWith('.html')) {
const originalSource = compilation.assets[filename].source();
const now = new Date().toISOString();
const newSource = `<!-- Build time: ${now} -->\n${originalSource}`;
compilation.assets[filename] = {
source: () => newSource,
size: () => newSource.length
};
}
}
}
);
});
}
}注意:必须用 thisCompilation 钩子获取 compilation 实例;processAssets 需指定 stage 保证执行顺序;修改 assets 要重写 source() 和 size() 方法。
立即学习“Java免费学习笔记(深入)”;
常用钩子与适用场景对照
不必死记所有钩子,按目的选常用几个即可:
-
compiler.hooks.run→ 构建开始前(如检查环境变量、连接远程服务) -
compiler.hooks.emit→ 所有 assets 生成完毕、写入磁盘前(适合最后校验或添加文件) -
compilation.hooks.optimizeChunks→ Chunk 优化阶段(可合并、拆分 chunk) -
compilation.hooks.chunkAsset→ 每个 chunk 生成 asset 后(适合按 chunk 注入 runtime) -
compilation.hooks.afterSeal→ Seal 完成后(此时 modules/chunks 已确定,适合统计分析)
调试 Plugin 的实用技巧
Plugin 逻辑不易调试,建议:
- 在回调函数里加
console.log,配合webpack --watch观察触发时机 - 用
debugger断点,启动时加node --inspect node_modules/webpack/bin/webpack.js - 打印关键对象结构,例如
console.dir(compilation.chunks, { depth: 2 }) - 优先使用
tap而非tapAsync或tapPromise,除非真需异步(如请求 API),否则易出错


















