Webpack流程图
重要的步骤:
init => run => compile => compilation => make => afterCompile => seal => codeGen => emit => done
plugin思路
plugin插件的思路就是在上面这些步骤间找个地方插进去,插进去调用的方法使用的是事件模型,hooks:
// 定义一个事件/钩子
this.hooks.eventName = new SyncHook(["arg1", "arg2"]);
// 监听一个事件/钩子
this.hooks.eventName.tap('监听事由', fn)
// 触发一个事件/钩子
this.hooks.eventName.call('arg1', 'arg2')
webpack源码中,每个步骤间都定义了hooks,你只要监听webpack生命周期里某个特定的钩子触发plugin,然后在函数中做自己想要做的事即可。
自己写webpack plugin
我们先来看一个plugin的源码:clean-webpack-plugin
这个插件的作用就是在dist文件生成前,清除之前的dist文件。
那么我们在webpack哪个步骤监听清除会比较好?
应该是在chunk即将写入硬盘中,emit的时候比较好,太早执行清空不太稳妥。
为了印证我的想法是不是对的,我们来看这个插件的关键代码:
apply(compiler: Compiler) {
if (!compiler.options.output || !compiler.options.output.path) {
// eslint-disable-next-line no-console
console.warn(
'clean-webpack-plugin: options.output.path not defined. Plugin disabled...',
);
return;
}
this.outputPath = compiler.options.output.path;
/**
* webpack 4+ comes with a new plugin system.
*
* Check for hooks in-order to support old plugin system
* webpack 5+ removed the old system, the check now breaks
*/
const hooks = compiler.hooks;
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
hooks.emit.tap('clean-webpack-plugin', (compilation) => {
this.handleInitial(compilation);
});
}
hooks.done.tap('clean-webpack-plugin', (stats) => {
this.handleDone(stats);
});
}
- hooks.emit.tap():清空dist
- hooks.done.tap():删除assets之外的文件
通过看源码就印证了我的推测。
- 一个 JavaScript 命名函数。
- 在插件函数的 prototype 上定义一个
apply
方法。 - 指定一个绑定到 webpack 自身的事件钩子。
- 处理 webpack 内部实例的特定数据。
- 功能完成后调用 webpack 提供的回调。
// 一个 JavaScript 命名函数。
function MyExampleWebpackPlugin() {
};
// 在插件函数的 prototype 上定义一个 `apply` 方法。
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
// 指定一个挂载到 webpack 自身的事件钩子。
compiler.plugin('webpacksEventHook', function(compilation /* 处理 webpack 内部实例的特定数据。*/, callback) {
console.log("This is an example plugin!!!");
// 功能完成后调用 webpack 提供的回调。
callback();
});
};
loader与plugin的区别
- Loader:它是一个转化器,将A文件编译成为B文件,例如:xx.md转化为xx.html,纯粹的文件转换过程。
- Plugin:它针对webpack整个打包过程,也就是webpack完整的生命周期,它在任何一个阶段都能参与,它能操作文件,并基于事件机制工作,它可以监听webpack打包过程中所有定义了hooks事件的钩子,并执行你需要的操作(可以调第三方插件,也可以自己写)。