Webpack5插件示例

1,272 阅读1分钟

创建插件

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

在插件开发中最重要的两个资源就是 compilercompilation 对象。理解它们的角色是扩展 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