插件机制:Tapable、compiler 与 compilation 的生命周期
本节目标
- 分清 loader 与 plugin 的根本区别
- 理解 Tapable 钩子、compiler 与 compilation 对象
- 知道常见内置/第三方插件(HtmlWebpackPlugin 等)挂在哪个阶段
前面 loader 管「单个文件怎么转译」,而 plugin(插件) 管的是「整个构建过程的某个时机做什么事」——比如:打包后自动生成 HTML、把 CSS 抽出去、注入版权 banner、生成资源清单。
Webpack 内部用 Tapable 这套「钩子(Hook)系统」来调度。你可以把它理解成一根时间轴上的许多「事件节点」,每个节点上可以「挂」你的逻辑。两个核心对象:
- compiler:一次构建的「总指挥」,从启动到结束只有一个,掌管全局配置和生命周期。
- compilation:一次「编译」的对象,代表当前这次打包的模块、chunk、资源。每次构建(或 watch 下的每次重编)都会有一个新的 compilation。
一个最简单的「使用插件」例子——自动生成引入 bundle 的 HTML:
# npm i -D html-webpack-pluginconst HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: { filename: 'bundle.js', path: __dirname + '/dist', clean: true },
plugins: [
new HtmlWebpackPlugin({ title: '我的应用' }), // 自动生成 dist/index.html 并注入 bundle
],
mode: 'development',
}插件怎么「挂」到钩子上?看一个插件内部长这样(概念示意):
// 插件是一个有 apply(compiler) 方法的类/对象
class MyPlugin {
apply(compiler) {
// compiler.hooks.emit 是「即将输出文件前」这个时机
compiler.hooks.emit.tap('MyPlugin', (compilation) => {
console.log('当前要输出的资源有:', Object.keys(compilation.assets))
})
}
}compiler.hooks.emit.tap('名字', 回调) 就是「在 emit 这个钩子上,注册一个监听」。Tapable 提供多种钩子:tap(同步)、tapAsync(异步回调)、tapPromise(异步 Promise)。HtmlWebpackPlugin 正是在 emit/资源生成阶段往 compilation.assets 里加了一个 index.html。
名词解释
Plugin(插件):在构建生命周期的某个钩子上「做事」的扩展点。它能操作整体产物(加文件、改内容、统计),能力比 loader 大得多。
Tapable:Webpack 内部基于「发布-订阅」的钩子系统,提供了 SyncHook、AsyncSeriesHook 等钩子类型,是插件机制的底层引擎。
Hook(钩子):构建时间轴上的一个事件节点(如 compile、make、emit、done),插件通过 .tap() 把逻辑挂上去。
Compiler / Compilation:compiler 是构建全程唯一的「总控」;compilation 是单次编译的「快照」,包含本次的模块、chunk、资源(assets)。
课后练习
练习 1:loader 和 plugin 的根本区别一句话怎么讲?
答案:loader 是「文件级翻译官」,只负责把单个源文件转成 JS 模块;plugin 是「流程级参与者」,能在构建的任意钩子上影响整体产物(增删改文件、读统计)。前者管「内容」,后者管「流程」。
练习 2:为什么插件用 .tap() 而不是普通函数调用注册?
答案:因为 Tapable 钩子本质是「监听器列表」。
.tap(name, fn)把你的函数注册进该钩子的队列,到对应时机 Webpack 会依次调用所有监听器——这是标准的事件订阅模型。
总结
插件机制的灵魂就一句话:Webpack 把构建拆成一条带钩子的时间轴,插件在钩子上 .tap 自己的逻辑。compiler 管全局、compilation 管单次编译的 resources,HtmlWebpackPlugin 之类就是挂在 emit 阶段往产物里塞 HTML。理解到这一层,下一步写你自己的插件就只是「选对钩子 + 写对逻辑」。这正是下一节的实操主题。