webpack源碼之tapable

引言

去年3月的時候當時寫了一篇 webpack2-update之路,到今天webpack已經到了4.2,更新挺快的,功能也在不斷的完善,webpack4特性之一就是零配置, webpack生命力真的很頑強,積極跟上環境的變化,響應社區的需求,不斷的迭代,由於parcel在其以前就有這個特性了。直接運行webpack命令,默認production模式,可是會有WARNING。

以下所示在package.json中啓動腳本配置node

"scripts": {
    "build": "webpack --mode production",  //代碼作了壓縮/做用域提高(就是將依賴模塊內容直接放到當前模塊內)/去掉了開發模式下存在的代碼/更容易使用輸出的資源文件(assets作了優化處理)
    "dev": "webpack-dev-server --open --mode development", //支持註釋/提示/source maps
  },

這種約定大於配置的開發方式,在不少框架中都存在, 默認的配置覆蓋了大部分用戶使用的場景,提升了大部分人的生產力。固然除了默認配置外還有其它一些特性,例如支持導入更多的模塊類型,能夠解析.json.wasm類型的文件等等。webpack

雖然使用形式上變化的這麼快, 可是其核心思想沒多大變化。 其中webpack內部有一個事件流機制,基於tapable,也是本文研究的對象,它的做用是將各個插件串聯起來,還有webpack中負責編譯的Compile也是tapable的實例,因此這個蠻重要的,下面詳細說一下。git

tapable概念

tapable相似於node中的EventEmitter,專一於自定義事件的觸發和處理,自身能夠被繼承或混入到其它模塊中。例如compile的實現就用到了tapable,以下所示。github

var Tapable = require("tapable");

function Compiler() {
    Tapable.call(this);
}

Compiler.prototype = Object.create(Tapable.prototype);

Hook分析

class Car {
    constructor() {
        this.hooks = {
            accelerate: new SyncHook(["newSpeed"]),
            break: new SyncHook(),
            calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])
        };
    }

}
const myCar = new Car();
//使用tap方法添加了一個消費者,其中tap的第一個參數,通常是用來確認插件的名稱
myCar.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));
myCar.hooks.accelerate.call('100')
//輸出   Accelerating to 100

說明 其中SyncHook繼承了Hook方法,主要做用是重寫了compile方法。而Hook內部維護了 this.taps = [],每次執行tap時,都會進行insert,call的時候經過web

this[name](...args)

進行執行,在call執行的時候其內部涉及到工廠模式,由於call的調用,須要先執行當前SyncHook的compile方法,用工廠模式的目的就是根據傳入的不一樣option返回不一樣的經過new Function拼接出的
處理邏輯函數,由於Hook有好幾種實現,在實現類的實例中添加的消費者能夠是sync,promise,async等等,都須要對應不一樣compile來進行處理。json

tapable使用分析

const {Tapable,SyncHook} = require("tapable");
const myCar = new Tapable();
myCar.hooks = {
    myHook: new SyncHook()
};
let speed = 0;
myCar.plugin("my-hook", () => speed+=2);
myCar.hooks.myHook.call();
myCar.plugin("my-hook", () => speed += 10);
myCar.hooks.myHook.call();
console.log(speed);
//輸出14

說明
plugin(name:string, handler:function):容許將一個自定義插件註冊到 Tapable 實例 的事件中。它的行爲和 EventEmitter 的 on() 方法類似,用來註冊一個處理函數/監聽器,來在信號/事件發生時作一些事情,他最終仍是調用hook.tap(tapOpt, options.fn)進行存儲。而call就所有取出來執行。segmentfault

總結

上面這些知識是理解插件和webpack運行原理的前置條件,更多內容待下次分解api

參考源碼版本說明
tapable: "1.0.0",
webpack: "^4.2.0",promise

參考連接
https://medium.com/webpack/we...
https://medium.com/webpack/we...
https://github.com/dwqs/blog/...
https://doc.webpack-china.org...
https://github.com/webpack/ta...框架

相關文章
相關標籤/搜索