webpack是一个很好用的打包工具,怎么配置和使用大家都比较熟悉了,其中在配置的过程中会用到很多plugin,如果想进一步了解webpack,就要了解plugin的工作机制,再进一步,就是自己动手封装一个plugin.
插件存在的环节:
Webpack 就像一条生产线,要经过一系列处理流程后才能将源文件转换成输出结果。
这条生产线上的每个处理流程的职责都是单一的,多个流程之间有存在依赖关系,只有完成当前处理后才能交给下一个流程去处理。
插件就像是一个插入到生产线中的一个功能,在特定的时机对生产线上的资源做处理。
首先看下webpack打包后输出文件的格式:
webpack打包过后是将一个一个的模块变成了一个对象,key是模块路径,值是模块里面的代码,只是代码被转化成了字符串,被放在eval环境里面,这样实现的基础是,webpack实现了一个函数_webpack_require()函数,用来引入不同的模块,进而处理模块之间的关系。_webpack_require可以有commonjs规范,cmd规范,具体实现方式可以参见我的另外两篇文章:
webpack plugin的工作机制
在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果
说明:可以安装lifecycle-webpack-plugin 插件来查看生命周期信息。
主要靠两个对象:
compiler对象和compilation对象
compiler对象:
- Compiler 对象包含了 Webpack 环境所有的的配置信息,包含 options,loaders,plugins 这些信息,这个对象在 Webpack 启动时候被实例化,它是全局唯一的,可以简单地把它理解为 Webpack 实例;
compilation对象
- Compilation 对象包含了当前的模块资源、编译生成资源、变化的文件等。当 Webpack 以开发模式运行时,每当检测到一个文件变化,一次新的 Compilation 将被创建。Compilation 对象也提供了很多事件回调供插件做扩展。通过 Compilation 也能读取到 Compiler 对象。
Compiler 和 Compilation 的区别在于:Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译。
webpack事件流(这里是老版本实现,新版本使用钩子函数)
核心模块:tabable
实现机制: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) {
});
注意:
有些事件是异步的,这些异步的事件会附带两个参数,第二个参数为回调函数,在插件处理完任务时需要调用回调函数通知 Webpack,才会进入下一处理流程。例如:
compiler.plugin('emit',function(compilation, callback) {
// 支持处理逻辑
// 处理完毕后执行 callback 以通知 Webpack
// 如果不执行 callback,运行流程将会一直卡在这不往下执行
callback();
});
关于常用api,这里仅列出,不做详细介绍:
插件可以用来修改输出文件、增加输出文件、甚至可以提升 Webpack 性能、等等,总之插件通过调用 Webpack 提供的 API 能完成很多事情。
常用:
1,读取输出资源、代码块、模块及其依赖
2,监听文件变化
3,修改输出资源
4,判断 Webpack 使用了哪些插件
手动编写一个插件
1,搭建一个基本架子:
2,添加两个事件
- done:在成功构建并且输出了文件后,Webpack 即将退出时发生;
- failed:在构建出现异常导致构建失败,Webpack 即将退出时发生;
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;
html-webpack-plugin实例:
参考:https://segmentfault.com/a/1190000012840742?utm_source=tuicool&utm_medium=referral