本文内容来自《深入浅出webpack》
Webpack 通过 Plugin 机制让其更加灵活,以适应各种应用场景。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
基础的Plugin
一个最基础的 Plugin 的代码是这样的:
class BasicPlugin{
// 在构造函数中获取用户给该插件传入的配置
constructor(options){
}
// Webpack 会调用 BasicPlugin 实例的 apply 方法给插件实例传入 compiler 对象
apply(compiler){
compiler.plugin('compilation',function(compilation) {
})
}
}
// 导出 Plugin
module.exports = BasicPlugin;
在使用这个 Plugin 时,相关配置代码如下:
const BasicPlugin = require('./BasicPlugin.js');
module.export = {
plugins:[
new BasicPlugin(options),
]
}
Webpack 启动后,在读取配置的过程中会先执行new BasicPlugin(options)初始化一个BasicPlugin获得其实例。在初始化compiler对象后,再调用basicPlugin.apply(compiler)给插件实例传入compiler对象。插件实例在获取到compiler对象后,就可以通过compiler.plugin(事件名称,回调函数)监听到Webpack 广播出来的事件。 并且可以通过 compiler 对象去操作Webpack。
Compiler 和 Compilation
在开发 Plugin 时最常用的两个对象就是 Compiler 和 Compilation,它们是 Plugin 和 Webpack 之间的桥梁。 Compiler 和 Compilation 的含义如下:
- Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在 Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例;
- Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler 对象。
Compiler 和 Compilation 的区别在于:Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译。
事件流
Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到webpack的事件流中,去改变生产线的运作。 Webpack 的事件流机制保证了插件的有序性,使得整个系统扩展性很好。
Webpack 的事件流机制应用了观察者模式,和 Node.js 中的 EventEmitter 非常相似。 Compiler 和 Compilation 都继承自 Tapable,可以直接在 Compiler 和 Compilation 对象上广播和监听事件,方法如下:
/**
* 广播出事件
* event-name 为事件名称,注意不要和现有的事件重名
* params 为附带的参数
*/
compiler.apply('event-name',params);
/**
* 监听名称为 event-name 的事件,当 event-name 事件发生时,函数就会被执行。
* 同时函数中的 params 参数为广播事件时附带的参数。
*/
compiler.plugin('event-name',function(params) {
});
同理,compilation.apply 和 compilation.plugin 使用方法和上面一致。 更多事件流参考webpack中文网
实战
编写一个EndWebpackPlugin,在Webpack 成功编译或者编译失败时执行对应的回调函数。
1.创建一个my-plugin文件
class EndWebpackPlugin{
constructor(doneCallback,failCallback){
// 存下在构造函数中传入的回调函数
this.doneCallback=doneCallback;
this.failCallback=failCallback;
}
apply(compiler){
compiler.plugin('done',(stats)=>{
// 在 done 事件中回调 doneCallback
this.doneCallback(stats)
});
compiler.plugin('failed',(err)=>{
// 在 failed 事件中回调 failCallback
this.failCallback(err)
});
}
}
module.exports = EndWebpackPlugin
2.在webpack.config.js中配置
module.exports = {
entry:{
index:'./src/index.js',
},
plugins:[
new EndWebpackPlugin((stats) => {
console.info('已成功构建',stats)
}, (err) => {
console.error('构建失败',err);
})
]
};