插件模式

在 webpack 构建系统中,能够通过插件进行定制,这赋予了无限的可能性。这使你可以创建自定义资源类型,执行唯一的构建修改,甚至可以使用中间件来增强 webpack 运行时。下面是在编写插件时非常有用一些 webpack 的功能。

检索遍历资源、chunk、模块和依赖

在执行完成编译的封存阶段后,编译的所有结构都可以遍历。

class MyPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
      // 检索每个(构建输出的)chunk:
      compilation.chunks.forEach((chunk) => {
        // 检索 chunk 中(内置输入的)的每个模块:
        chunk.getModules().forEach((module) => {
          // 检索模块中包含的每个源文件路径:
          module.buildInfo &&
            module.buildInfo.fileDependencies &&
            module.buildInfo.fileDependencies.forEach((filepath) => {
              // 我们现在已经对源结构有不少了解……
            });
        });

        // 检索由 chunk 生成的每个资源文件名:
        chunk.files.forEach((filename) => {
          // 获取 chunk 生成的每个文件的资源源代码:
          var source = compilation.assets[filename].source();
        });
      });

      callback();
    });
  }
}
module.exports = MyPlugin;
  • compilation.modules:编译后的(内置输入的)模块数组。每个模块管理控制来源代码库中的原始文件的构建。
  • module.fileDependencies:模块中引入的源文件路径构成的数组。这包括源 JavaScript 文件本身(例如:index.js)以及它所需的所有依赖资源文件(样式表、图像等)。审查依赖,可以用于查看一个模块有哪些从属的源文件。
  • compilation.chunks:编译后的(构建输出的)chunk 集合。每个 chunk 所管理控制的最终渲染资源的组合。
  • chunk.getModules():chunk 中引入的模块构成的数组。通过扩展可以审查每个模块的依赖,来查看哪些原始源文件被注入到 chunk 中。
  • chunk.files:chunk 生成的输出文件名构成的集合。你可以从 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 中,就可以将其添加到观察图中。

监听 chunk 的修改

类似于观察图,监听 chunk(或者模块,就当前情况而言)的修改也很简单,通过在编译时跟踪它们的哈希来实现。

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;

1 位译者

4 位贡献者

nveenjainEugeneHlushkobenglynnYucohny