插件的构成
一个插件由以下几个部分构成
- 一个具名的 Javascript 函数
- 在原型上定义 apply 方法
- 指定一个触及到 webpack 本身的事件钩子
- 操作 webpack 内部实例特定数据
- 在实现功能之后调用webpack 提供的 Callback
apply 方法
插件是由一个构造函数(此构造函数的 prototype 对象具有 apply 方法)所实例化出来的。这个 apply 方法在安装插件时,会被 webpack compilier 调用一次。apply 方法可以接收一个 webpck compiler 对象的引用,从而可以在回调函数中访问到 compilier 对象。
compiler 和 compilation
在插件开发中最重要的两个资源就是 compiler 和 compilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
class HelloCompilationPlugin {
apply(compiler) {
// tap(触及) 到 compilation hook,回调函数中,会将 compilation 对象作为参数,
compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => {
// 现在,通过 compilation 对象,我们可以 tap(触及) 到各种可用的 hooks 了
compilation.hooks.optimize.tap('HelloCompilationPlugin', () => {
console.log('正在优化资源。');
});
});
}
}
module.exports = HelloCompilationPlugin;
异步事件钩子
tap 用于触发同步的钩子,tabAsync 或者 tabPromise 用来触发异步的钩子
tabAsync
在使用 tapAsync 方法 tap 插件时,我们需要调用 callback,此 callback 将作为最后一个参数传入函数
class HelloAsyncPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('HelloAsyncPlugin', (compilation, callback) => {
// 做一些异步的事情……
setTimeout(function() {
console.log('Done with async work...');
callback();
}, 1000);
});
}
}
module.exports = HelloAsyncPlugin;
tabPromise
此方法需要返回一个 Promise,此 promise 将在我们的异步任务完成时 resolve
class HelloAsyncPlugin {
apply(compiler) {
compiler.hooks.emit.tapPromise('HelloAsyncPlugin', compilation => {
// 返回一个 Promise,在我们的异步任务完成时 resolve……
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log('异步工作完成……');
resolve();
}, 1000);
});
});
}
}
module.exports = HelloAsyncPlugin;
插件模式
在执行完成编译的封存阶段(seal)之后,编译(compilation)的所有结构都可以遍历
class MyPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
// 检索每个(构建输出的)chunk:
compilation.chunks.forEach(chunk => {
// 检索 chunk 中(内置输入的)的每个模块:
chunk.modules.forEach(module => {
// 检索模块中包含的每个源文件路径:
module.fileDependencies.forEach(filepath => {
// 我们现在已经对源结构有不少了解……
});
});
// 检索由 chunk 生成的每个资源(asset)文件名:
chunk.files.forEach(filename => {
// Get the asset source for each file generated by the chunk:
var source = compilation.assets[filename].source();
});
});
callback();
});
}
}
module.exports = MyPlugin;
compilation.modules
: 编译后的模块数组module.fileDependencies
: 模块中引入的源文件路径构成的数组compilation.chunks
: 编译后的代码块chunk.modules
: chunk 中引入的模块构成的数组chunk.files
: chunk 生成的输出文件名构成的数组。你可以从 compilation.assets 表中访问这些资源来源。