原做者的webpack教程 part 2 tapable

简介

这是一个系列的文章,目前一共有3篇,是原做者在去年开始连载的系列教程, 我看了一下没看太懂, 翻译出来,你们探讨一下, 这个是第二部分, 第一部分是webpack 的各个包的功能介绍.就不翻译了.想看的就按原文连接 你就能找到所有的系列vue

深刻了解

就算这篇教程和上一篇教程都是关于如何向webpack贡献代码的,可是我想先花费一些时间给大家说一下你将会在不少项目中看见的范例(不少项目指的应该是 webpack 里面分布的包)webpack

注意: 对于想向webpack 贡献代码的小伙伴, 或者想本身写插件的小伙伴,这对大家尤为有用.git

tapable

就像上一部分说的,tapable 是webpack 的核心构建块,(webpack是又不少个块组成的),类和对象都继承tapable是tapable 的实例,下面有一个很是简单的例子.github

const Tapable = require('tapable');
class Compiler extends Tapable {
  constructor() {  
    this.foo = "43";
    this.applyPluginsAsync("run", this, function(err, done) {
      if (done) {this.doRunStuffAfterSuccess()}
    }
this.applyPlugins("done", stats); 
  }
}

tapable 添加了插件能够挂钩进去的事件触发功能, 你能够在你使用的任何webpack库中搜索this.applyPlugins 找到挂钩的事件.(通常是插件源码)web

解剖一个插件

一个webpack 插件的样子最好描述成一个实现了 apply() 方法的类,这个方法会在tapable 实例(一般指Compiler)的初始化事件钩子中被调用,体验一下下面的例子.设计模式

class MyFirstPlugin {
  apply(compiler) {
    compiler.plugin("run", function(compiler, cb) {
      console.log("webpack is about to start bundling");
      cb(); // cb() signals to the compiler that this asnyc hook is finished. 
    });
compiler.plugin("done", function(stats) {
      console.log("webpack is finished bundling");
    });  
  }
}

这里有几个关键的点架构

  • compiler实例被传进去apply 方法,这给了你一个访问tapable实例的途径,而后你就能够 'tap'(我估计是事件流的概念,跟绑定的概念类似,具体能够去了解一下事件流) 进去tapable 触发的事件.
  • 要钩进去事件里面,就必需要在tapable实例上调用.plugins函数,而后指定事件的名字,和一个执行你的逻辑的回调.
  • 若是这个事件是异步的,回调事件的最后一个参数,将会是一个回调钩子,他会在咱们的自定义逻辑执行完毕后,发出信号.

如何去注册一个插件

tapable实例经过调用apply方法,传入一个nwe 出来的插件实例来注册插件,例如,若是咱们要注册上面的插件,咱们只须要这样写,compiler.apply(new MyFirstPlugin())app

插件的设计模式

webpack 的插件都是设计成单一目的的,也就是一个插件只能有一个功能.观察下面的代码;异步

var SingleEntryPlugin = require("./SingleEntryPlugin");
var MultiEntryPlugin = require("./MultiEntryPlugin");

function EntryOptionPlugin() {}
module.exports = EntryOptionPlugin;

EntryOptionPlugin.prototype.apply = function(compiler) {
    compiler.plugin("entry-option", function(context, entry) {
        function itemToPlugin(item, name) {
            if(Array.isArray(item))
                return new MultiEntryPlugin(context, item, name);
            else
                return new SingleEntryPlugin(context, item, name);
        }
        if(typeof entry === "string" || Array.isArray(entry)) {
            compiler.apply(itemToPlugin(entry, "main"));
        } else if(typeof entry === "object") {
            Object.keys(entry).forEach(function(name) {
                compiler.apply(itemToPlugin(entry[name], name));
            });
        }
        return true;
    });
};

EntryOptionPlugin’s 惟一的目的就是要钩(这里的勾是钩子函数的概念)进去compiler实例,以得到全部在配置文件里面定义的对象的入口点,而后转换为SingleEntryPlugin实例 或者MultiEntryPlugin实例的值,而后把这些插件传递回compiler.aaply()去注册他们.函数

学习源码,写你本身的插件,问问题,作笔记,使用这些难以置信(估计做者在这里幽默了一番,这些方法并不难以执行)的方法,你不只能学会属于本身的技能,还可让你成为webpack的下一个贡献者,最后在一天结束的时候,感到颇有趣.

webpack中的Tapable 实例 (你能够插件化的类)

如今你在webpack 和他的插件系统如何工做上有必定的了解,让咱们来看一下被webpack 使用的tapable.

  • Compiler --- 编译运行时,包含了全部的编译钩子的顶级模块,插件能够钩进runemit这样的事件.
  • Compilation--- webpack Compiler 类的产物,Compiler 类返回Compilation‘s, 这是你的应用的依赖图的入口,Compilation 包含了optimize-modules, seal and optimize-chunk-assets这样的钩子,全部的优化,和总体程序的编译,和工具,都会在Compilation 执行.
  • Resolver(s) ---- webpack 解析器 是由enhanced-resolve. 这个插件建立的.插入webpack解析器的插件,是用于定制模块解析策略(详情请了解策略模式)的,你的webpack的配置的resolve对象的全部属性对应于已经应用的指定的插件解析器.
  • NormalModuleFactoty --- 这个东西是一个胶水,把 resolver, loaderNormalModule 的建立物绑定在一块儿,你会用到的生命周期钩子包括before-resolve, after-resolve, 和 create-module, 除此以外,loaders 针对每个模块运行,他能够从他们的原的文件,转换成能够被添加进入webpack的 chunk的东西(例如vue-loader 就会把vue文件转换成 对象)
  • ContextModuleFatory --- 这个插件除了,能够动态requires 之外,其余的都跟上面那个同样.
  • Templelate --- 由于webpack 捆绑的时候,会生成bundle 代码, Templelate 实例 就是负责绑定的模块数据产出时的结构
  • Temple Subclasses --- 它有许多级别的模版, MainTemplate (运行时 绑定(bundle)包装器), ChunkTemplate 等等....(这里我建议大家看原版吧,实在翻译不出)
  • Parser --- webpack Parser 是webpack 源码中最特别的一个tapable实例之一,parser 实例是一个由 acorn ast 分析器 提供功能的tapable 实例.
前面全部的类均可以发出Tapable事件所以能够为他们编写插件.

译者注: 原文下面都是一些让你努力学习,每天向上,让你选择一个源码去看,而后是最紧要系你以为开心,之类的话,我选择不译.

tapable 库已经通过更新, 上面提到的方法已经废弃了,可是基本架构并无改变, 具体请关注github的tapable仓库
相关文章
相关标签/搜索