插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建加载器更加高级,因为你将需要理解一些 webpack 底层的内部特性来做相应的勾子,所以做好阅读一些源码的准备!
在插件开发中最重要的两个资源就是 compiler
和 compilation
对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
compiler
对象代表了完整的 webpack 环境配置。这个对象在启动 webpack
时被一次性建立,并在所有可操作的设置中被配置,包括原始配置,加载器和插件。当在 webpack
环境中应用一个插件时,插件将收到一个编译器对象的引用。可以使用它来访问 webpack 的主环境。
compilation
对象代表了一次单一的版本构建和生成资源。当运行 webpack
开发环境中间件时,每当检测到一个文件变化,一次新的编译将被创建,从而生成一组新的编译资源。一个编译对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。编译对象也提供了很多关键点回调供插件做自定义处理时选择使用。
这两个成员是任何 webpack 插件不可或缺的部分(特别是 compilation
),如果开发者阅读它们的源码并进行熟悉,将获益匪浅:
插件都是被实例化的带有 apply
原型方法的对象。这个 apply
方法在安装插件时将被 webpack 编译器调用一次。apply
方法提供了一个对应的编译器对象的引用,从而可以访问到相关的编译器回调。一个简单的插件结构如下:
function HelloWorldPlugin(options) {
// 使用配置(options)设置插件实例
}
HelloWorldPlugin.prototype.apply = function(compiler) {
compiler.plugin('done', function() {
console.log('Hello World!');
});
};
module.exports = HelloWorldPlugin;
然后要安装这个插件,只需要在你的 webpack 配置的 plugin
数组中加入一个实例:
var HelloWorldPlugin = require('hello-world');
var webpackConfig = {
// ... 这里是其他配置 ...
plugins: [
new HelloWorldPlugin({options: true})
]
};
使用编译器对象时,你可以绑定提供了编译对象引用的回调拿到每次新的编译对象。这些编译对象提供了构建流程中很多步骤的回调来做勾子。
function HelloCompilationPlugin(options) {}
HelloCompilationPlugin.prototype.apply = function(compiler) {
// 设置回调来访问编译对象:
compiler.plugin("compilation", function(compilation) {
// 现在设置回调来访问编译中的步骤:
compilation.plugin("optimize", function() {
console.log("Assets are being optimized.");
});
});
};
module.exports = HelloCompilationPlugin;
关于 compiler
和 compilation
的更多可用的回调和信息,以及其它重要的对象,请参考 插件 文档。
有一些编译插件中的步骤是异步的,这样要传递一个回调函数,并且在插件运行结束时回调必须被调用。
function HelloAsyncPlugin(options) {}
HelloAsyncPlugin.prototype.apply = function(compiler) {
compiler.plugin("emit", function(compilation, callback) {
// 做一些异步处理……
setTimeout(function() {
console.log("Done with async work...");
callback();
}, 1000);
});
};
module.exports = HelloAsyncPlugin;
一旦能我们深入理解 webpack 编译器和每个独立的编译,我们依赖 webpack 引擎将有无限多的事可以做。我们可以重新格式化已有的文件,创建衍生的文件,或者制作全新的生成文件。
让我们来写一个简单的示例插件,生成一个叫做 filelist.md
的新文件;文件内容是所有构建生成的文件的列表。这个插件大概像下面这样:
function FileListPlugin(options) {}
FileListPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
// 创建一个头部字符串:
var filelist = 'In this build:\n\n';
// 检查所有编译好的资源文件:
// 为每个文件名新增一行
for (var filename in compilation.assets) {
filelist += ('- '+ filename +'\n');
}
// 把它作为一个新的文件资源插入到 webpack 构建中:
compilation.assets['filelist.md'] = {
source: function() {
return filelist;
},
size: function() {
return filelist.length;
}
};
callback();
});
};
module.exports = FileListPlugin;
原文:https://webpack.js.org/development/how-to-write-a-plugin/