插件可以访问 webpack 打包生命周期中涉及的资源,做一些额外的操作。

在 webpack 配置文件中有个 plugins 的选项,接收用户自定义的插件。

  1. // webpack.config.js
  2. module.exports = {
  3. plugins: [
  4. new MyCustomPlugin()
  5. ],
  6. }

1 定义

插件通常定义如下所示,取一个有 apply 方法的类

  1. class MyExampleWebpackPlugin {
  2. constructor(options) {
  3. this.options = options;
  4. }
  5. // Define `apply` as its prototype method which is supplied with
  6. // compiler as its argument
  7. apply(compiler) {
  8. // Specify the event hook to attach to
  9. compiler.hooks.emit.tapAsync(
  10. 'MyExampleWebpackPlugin',
  11. (compilation, callback) => {
  12. callback();
  13. }
  14. );
  15. }
  16. }

2 hook

webpack 内部使用 tapable 分发事件。一般通过如下形式注册

compiler.hooks.someHook.tap('MyPlugin', (params) => {
  /* ... */
});

其中 someHook 是某个生命周期的 hook,如:

  • emit (AsyncSeriesHook) : 在打包输出前触发
  • afterEmit (AsyncSeriesHook) : 在打包输出后触发

全部参考:https://webpack.js.org/api/compiler-hooks/

2.1 文件读取

负责文件生成的 hook 叫 emit,它是一个 AsyncSeriesHook 。

emit 生成文件阶段,读取的是 compilation.assets 对象的值

module.exports = class ZipPlugin {
  constructor(options) {
    this.options = options;
  }
  apply(compiler) {
    compiler.hooks.emit.tapAsync('ZipPlugin', (compilation, cb) => {
        for (let filename in compilation.assets) {
            const source = compilation.assets[filename].source();
                        // do something
        }
                // call cb()
    });
  }
}

2.2 文件写入

使用 webpack-sources 包进行写入

const RawSource = require('webpack-sources').RawSource;

compilation.assets[outputPath] = new RawSource(content);

Reference