深入Plugin
Loader是专注于不同类型模块的转换,某些功能是Loader无法实现的,就需要使用Plugin来实现。因为Webpack使用了Tapable,所以在构建的时候能够发出很多事件,而Plugin在收到自己感兴趣的事件后,就会执行相应的操作。
一个基础的插件结构如下:
- 一个JavaScript命名函数。
- 在插件函数的prototype上定义一个apply方法。
- 指定一个绑定到Webpack自身的事件钩子。
- 处理Webpack内部实例的特定数据。
- 功能完成后调用Webpack提供的回调。
class Myplugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.emit.tap('Myplug', (compilation) => {
})
}
}
module.exports = Myplugin;
插件中一个必不可少的函数就是apply,这个apply方法在安装插件时,会被Webpack Compiler调用一次。apply方法可以接收一个Webpack Compiler对象的引用,从而可以在函数中访问到Compiler对象。
Compiler和Compilation
在插件开发中最重要的两个资源对象就是Compiler和Compilation 对象。理解它们的角色是扩展Webpack引擎重要的第一步。
Compiler对象代表了完整的Webpack环境配置。这个对象在启动Webpack时被一次性建立,并配置好所有可操作的设置,包括Options,Loader和Plugin。当在Webpack环境中应用一个插件时,插件将收到此Compiler对象的引用。可以使用它来访问Webpack的主环境。
Compilation对象代表了一次资源版本构建。当以监听模式运行Webpack时,每当检测到一个文件变化,就会创建一个新的Compilation,从而生成一组新的编译资源。一个Compilation对象包含了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。Compilation对象也提供了很多关键时机的回调,以供插件做自定义处理时选择使用。
编写一个简单的Plugin
在编写插件之前,先看Webpack官网给出的一个插件编写的演示:
class FileListPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => {
// 在生成文件中,创建一个头部字符串:
let filelist = 'In this build:\n\n';
// 遍历所有编译过的资源文件,
// 对于每个文件名称,都添加一行内容。
Object.entries(compilation.assets).forEach(([filename, proObj]) => {
filelist += ('- ' + filename + ' ' + proObj.size() + '\n');
})
// 将这个列表作为一个新的文件资源,插入到 webpack 构建中:
compilation.assets[this.options.filename] = {
source: function () {
return filelist;
},
size: function () {
return filelist.length;
}
};
callback();
})
}
}
module.exports = FileListPlugin;
该插件是严格按照插件的定义来实现的,其功能是生成一个统计输出资源信息的文件。
下面我们来实现一个在打包完成后,自动提交代码到Gi仓库的插件:
const shell = require("shelljs");
class MyPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
compiler.hooks.done.tap('MyPlugin', () => {
shell.exec('git add .');
shell.exec(`git commit -m'${this.options.commitInfo}'`);
shell.exec('git push');
})
}
}
module.exports = MyPlugin;
使用该插件之前,假设你的项目已经初始化好了Git的相关配置。该插件使用方式如下:
module.exports = {
plugins: [
new MyPlugin({
commitInfo: '自定义插件使用'
})
]
}
本章节提供案例源码下载:https://gitee.com/mvc_ydb/webpack/blob/master/deepPlugin.zip