Plugin 模式

插件为在 webpack 构建系统中进行自定义提供了无限的机会。这允许你创建自定义资源类型、执行独特的构建修改,甚至在使用中间件时增强 webpack 运行时。以下是编写插件时会用到的一些 webpack 功能。

探索资源、代码块、模块和依赖

编译完成后,编译中的所有结构都可以被遍历。

class MyPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
      // Explore each chunk (build output):
      compilation.chunks.forEach((chunk) => {
        // Explore each module within the chunk (built inputs):
        chunk.getModules().forEach((module) => {
          // Explore each source file path that was included into the module:
          module.buildInfo &&
            module.buildInfo.fileDependencies &&
            module.buildInfo.fileDependencies.forEach((filepath) => {
              // we've learned a lot about the source structure now...
            });
        });

        // Explore each asset filename generated by the chunk:
        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:模块中包含的源文件路径数组。这包括源 JavaScript 文件本身(例如:index.js),以及它所依赖的所有资源文件(样式表、图片等)。检查依赖关系有助于查看哪些源文件属于一个模块。
  • compilation.chunks:编译中的一个代码块 (构建输出) 集合。每个代码块管理最终渲染资产的组成。
  • chunk.getModules():包含在代码块中的模块数组。由此,你可以查看每个模块的依赖项,以了解哪些原始源文件进入了该代码块。
  • chunk.files:由该代码块生成的输出文件名集合 (Set)。你可以从 compilation.assets 表中访问这些资源源。

监控监听图

运行 webpack 中间件时,每次编译都包含一个 fileDependencies 集合 (Set)(哪些文件正在被监听)以及一个 fileTimestamps 映射 (Map),它将监听的文件路径映射到时间戳。这些对于检测编译中哪些文件发生了变化非常有用。

class MyPlugin {
  constructor() {
    this.startTime = Date.now();
    this.prevTimestamps = new Map();
  }
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
      const changedFiles = Array.from(compilation.fileTimestamps.keys()).filter(
        (watchfile) => {
          return (
            (this.prevTimestamps.get(watchfile) || this.startTime) <
            (compilation.fileTimestamps.get(watchfile) || Infinity)
          );
        }
      );

      this.prevTimestamps = compilation.fileTimestamps;
      callback();
    });
  }
}

module.exports = MyPlugin;

你也可以将新的文件路径添加到监听图中,以便在这些文件更改时触发编译。将有效的文件路径添加到 compilation.fileDependencies 集合 (Set) 中,即可将其添加到监听文件。

已更改的代码块

与监听图类似,你可以在编译中监控已更改的代码块(或模块,就此而言),通过跟踪它们的哈希值。

class MyPlugin {
  constructor() {
    this.chunkVersions = {};
  }
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
      var changedChunks = compilation.chunks.filter((chunk) => {
        var oldVersion = this.chunkVersions[chunk.name];
        this.chunkVersions[chunk.name] = chunk.hash;
        return chunk.hash !== oldVersion;
      });
      callback();
    });
  }
}

module.exports = MyPlugin;

3 贡献者

nveenjainEugeneHlushkobenglynn