加载中...

如何编写一个插件?


插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建加载器更加高级,因为你将需要理解一些 webpack 底层的内部特性来做相应的勾子,所以做好阅读一些源码的准备!

编译器(Compiler)和编译(Compilation)

在插件开发中最重要的两个资源就是 compilercompilation 对象。理解它们的角色是扩展 webpack 引擎重要的第一步。

  • compiler 对象代表了完整的 webpack 环境配置。这个对象在启动 webpack 时被一次性建立,并在所有可操作的设置中被配置,包括原始配置,加载器和插件。当在 webpack 环境中应用一个插件时,插件将收到一个编译器对象的引用。可以使用它来访问 webpack 的主环境。

  • compilation 对象代表了一次单一的版本构建和生成资源。当运行 webpack 开发环境中间件时,每当检测到一个文件变化,一次新的编译将被创建,从而生成一组新的编译资源。一个编译对象表现了当前的模块资源、编译生成资源、变化的文件、以及被跟踪依赖的状态信息。编译对象也提供了很多关键点回调供插件做自定义处理时选择使用。

这两个成员是任何 webpack 插件不可或缺的部分(特别是 compilation),如果开发者阅读它们的源码并进行熟悉,将获益匪浅:

基本插件架构

插件都是被实例化的带有 apply 原型方法的对象。这个 apply 方法在安装插件时将被 webpack 编译器调用一次。apply 方法提供了一个对应的编译器对象的引用,从而可以访问到相关的编译器回调。一个简单的插件结构如下:

function HelloWorldPlugin(options) {
  // 使用配置(options)设置插件实例
}

HelloWorldPlugin.prototype.apply = function(compiler) {
  compiler.plugin('done', function() {
    console.log('Hello World!');
  });
};

module.exports = HelloWorldPlugin; 

然后要安装这个插件,只需要在你的 webpack 配置的 plugin 数组中加入一个实例:

var HelloWorldPlugin = require('hello-world');

var webpackConfig = {
  // ... 这里是其他配置 ...
  plugins: [
    new HelloWorldPlugin({options: true})
  ]
}; 

访问编译

使用编译器对象时,你可以绑定提供了编译对象引用的回调拿到每次新的编译对象。这些编译对象提供了构建流程中很多步骤的回调来做勾子。

function HelloCompilationPlugin(options) {}

HelloCompilationPlugin.prototype.apply = function(compiler) {

  // 设置回调来访问编译对象:
  compiler.plugin("compilation", function(compilation) {

    // 现在设置回调来访问编译中的步骤:
    compilation.plugin("optimize", function() {
      console.log("Assets are being optimized.");
    });
  });
};

module.exports = HelloCompilationPlugin; 

关于 compilercompilation 的更多可用的回调和信息,以及其它重要的对象,请参考 插件 文档。

异步编译插件

有一些编译插件中的步骤是异步的,这样要传递一个回调函数,并且在插件运行结束时回调必须被调用。

function HelloAsyncPlugin(options) {}

HelloAsyncPlugin.prototype.apply = function(compiler) {
  compiler.plugin("emit", function(compilation, callback) {

    // 做一些异步处理……
    setTimeout(function() {
      console.log("Done with async work...");
      callback();
    }, 1000);

  });
};

module.exports = HelloAsyncPlugin; 

示例

一旦能我们深入理解 webpack 编译器和每个独立的编译,我们依赖 webpack 引擎将有无限多的事可以做。我们可以重新格式化已有的文件,创建衍生的文件,或者制作全新的生成文件。

让我们来写一个简单的示例插件,生成一个叫做 filelist.md 的新文件;文件内容是所有构建生成的文件的列表。这个插件大概像下面这样:

function FileListPlugin(options) {}

FileListPlugin.prototype.apply = function(compiler) {
  compiler.plugin('emit', function(compilation, callback) {
    // 创建一个头部字符串:
    var filelist = 'In this build:\n\n';

    // 检查所有编译好的资源文件:
    // 为每个文件名新增一行
    for (var filename in compilation.assets) {
      filelist += ('- '+ filename +'\n');
    }

    // 把它作为一个新的文件资源插入到 webpack 构建中:
    compilation.assets['filelist.md'] = {
      source: function() {
        return filelist;
      },
      size: function() {
        return filelist.length;
      }
    };

    callback();
  });
};

module.exports = FileListPlugin; 

原文:https://webpack.js.org/development/how-to-write-a-plugin/


还没有评论.