创建插件
webpack 插件由以下组成:
- 一个 JavaScript 命名函数或 JavaScript 类。
- 在插件函数的 prototype 上定义一个
apply方法。 - 指定一个绑定到 webpack 自身的事件钩子。
- 处理 webpack 内部实例的特定数据。
- 功能完成后调用 webpack 提供的回调。
// 一个 JavaScript 类
class MyExampleWebpackPlugin {
// 在插件函数的 prototype 上定义一个 `apply` 方法,以 compiler 为参数。
apply(compiler) {
// 指定一个挂载到 webpack 自身的事件钩子。
compiler.hooks.emit.tapAsync(
'MyExampleWebpackPlugin',
(compilation, callback) => {
console.log('这是一个示例插件!');
console.log(
'这里表示了资源的单次构建的 `compilation` 对象:',
compilation
);
// 用 webpack 提供的插件 API 处理构建过程
compilation.addModule(/* ... */);
callback();
}
);
}
}
Compiler 和 Compilation
在插件开发中最重要的两个资源就是 compiler 和 compilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。
class HelloCompilationPlugin {
apply(compiler) {
// 指定一个挂载到 compilation 的钩子,回调函数的参数为 compilation 。
compiler.hooks.compilation.tap('HelloCompilationPlugin', (compilation) => {
// 现在可以通过 compilation 对象绑定各种钩子
compilation.hooks.optimize.tap('HelloCompilationPlugin', () => {
console.log('资源已经优化完毕。');
});
});
}
}
module.exports = HelloCompilationPlugin;
示例
/**
* 本插件自动在每个输出的 js 文件头尾加上 performance.mark ,在尾部加上 nperformance.measure 来测量 js 的执行时长
* 然后可自己用 performance.getEntriesByType('measure'); 来收集数据
*/
class PerformanceMeasurePlugin {
constructor() {}
apply(compiler) {
const pluginName = PerformanceMeasurePlugin.name;
const { webpack } = compiler;
const { Compilation } = webpack;
// 【compiler钩子】thisCompilation: 初始化 compilation 时调用,在触发 compilation 事件之前调用。
compiler.hooks.thisCompilation.tap(pluginName, (compilation) => {
// 【compilation钩子】processAssets
compilation.hooks.processAssets.tap({
name: pluginName,
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, // @see node_modules/webpack/lib/Compilation.js 和 https://webpack.docschina.org/api/compilation-hooks/#list-of-asset-processing-stages 查看 15个 PROCESS_ASSETS_STAGE_*
}, (assets) => {
// assets — 普通对象,其中 key 是 asset 的路径名,value 是 asset 的数据,具体的代表请参考 Source。
for (let pathname in assets) {
if (!pathname.endsWith('.js')) {
continue
}
let source = assets[pathname].source()
let start = `${pathname}-start`
let end = `${pathname}-end`
source = `performance.mark("${start}");
${source}
performance.mark("${end}");
performance.measure("${pathname}", "${start}", "${end}");`;
assets[pathname] = {
source: function() { return source },
size: function () {
return source.length
}
}
}
})
})
}
}
module.exports = PerformanceMeasurePlugin