原做者的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倉庫
相關文章
相關標籤/搜索