webpack编写一个plugin插件

插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者能够引入它们本身的行为到 webpack 构建流程中。建立插件比建立 loader 更加高级,由于你将须要理解一些 webpack 底层的内部特性来实现相应的钩子。webpack

1、插件由如下部分构成

  一、一个具名 JavaScript 函数web

  二、在它的原型上定义 apply 方法。api

  三、指定一个触及到 webpack 自己的 事件钩子数组

  四、操做 webpack 内部的实例特定数据。promise

  五、在实现功能后调用 webpack 提供的 callback。  架构

// 一个 JavaScript class
class MyExampleWebpackPlugin {
  // 将 `apply` 定义为其原型方法,此方法以 compiler 做为参数
  apply(compiler) {
    // 指定要附加到的事件钩子函数
    compiler.hooks.emit.tapAsync(
      'MyExampleWebpackPlugin',
      (compilation, callback) => {
        console.log('This is an example plugin!');
        console.log('Here’s the `compilation` object which represents a single build of assets:', compilation);

        // 使用 webpack 提供的 plugin API 操做构建结果
        compilation.addModule(/* ... */);

        callback();
      }
    );
  }
}

2、基本插件架构

插件是由一个构造函数(此构造函数上的 prototype 对象具备 apply 方法)的所实例化出来的。这个 apply方法在安装插件时,会被 webpack compiler 调用一次。apply 方法能够接收一个 webpack compiler 对象的引用,从而能够在回调函数中访问到 compiler 对象。app

class HelloWorldPlugin {
  apply(compiler) {
    compiler.hooks.done.tap('Hello World Plugin', (
      stats /* 在 hook 被触及时,会将 stats 做为参数传入。 */
    ) => {
      console.log('Hello World!');
    });
  }
}

module.exports = HelloWorldPlugin;

而后,要使用这个插件,在你的 webpack 配置的 plugins 数组中添加一个实例:异步

// webpack.config.js
var HelloWorldPlugin = require('hello-world');

module.exports = {
  // ... 这里是其余配置 ...
  plugins: [new HelloWorldPlugin({ options: true })]
};

3、compiler 和 compilation

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

class HelloCompilationPlugin {
  apply(compiler) {
    // tap(触及) 到 compilation hook,而在 callback 回调时,会将 compilation 对象做为参数,
    compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => {
      // 如今,经过 compilation 对象,咱们能够 tap(触及) 到各类可用的 hooks 了
      compilation.hooks.optimize.tap('HelloCompilationPlugin', () => {
        console.log('正在优化资源。');
      });
    });
  }
}

module.exports = HelloCompilationPlugin;

这里列出 compilercompilation 和其余重要对象上可用 hooks,请查看 插件 API 文档。函数

4、异步事件钩子

有些插件 hooks 是异步的。想要 tap(触及) 某些 hooks,咱们可使用同步方式运行的 tap 方法,或者使用异步方式运行的 tapAsync 方法或 tapPromise 方法。

tapAsync

在咱们使用 tapAsync 方法 tap 插件时,咱们须要调用 callback,此 callback 将做为最后一个参数传入函数。

class HelloAsyncPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapAsync('HelloAsyncPlugin', (compilation, callback) => {
      // 作一些异步的事情……
      setTimeout(function() {
        console.log('Done with async work...');
        callback();
      }, 1000);
    });
  }
}

module.exports = HelloAsyncPlugin;

tapPromise

在咱们使用 tapPromise 方法 tap 插件时,咱们须要返回一个 promise,此 promise 将在咱们的异步任务完成时 resolve。

class HelloAsyncPlugin {
  apply(compiler) {
    compiler.hooks.emit.tapPromise('HelloAsyncPlugin', compilation => {
      // 返回一个 Promise,在咱们的异步任务完成时 resolve……
      return new Promise((resolve, reject) => {
        setTimeout(function() {
          console.log('异步工做完成……');
          resolve();
        }, 1000);
      });
    });
  }
}

module.exports = HelloAsyncPlugin;

5、示例

一旦能咱们深刻理解 webpack compiler 和每一个独立的 compilation,咱们就能经过 webpack 引擎自己作到无穷无尽的事情。咱们能够从新格式化已有的文件,建立衍生的文件,或者制做全新的生成文件。

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

class FileListPlugin {
  apply(compiler) {
    // emit 是异步 hook,使用 tapAsync 触及它,还可使用 tapPromise/tap(同步)
    compiler.hooks.emit.tapAsync('FileListPlugin', (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;

 6、参考博客:

  http://www.javashuo.com/article/p-ttmejbzp-he.html

相关文章
相关标签/搜索