文章目錄
- 由淺入深學習Tapable
- Tapable是什么
- Tapable的Hook分類
- 同步和異步的
- 使用
- Sync*同步類型鉤子
- 基本使用
- bail
- Loop
- Waterfall
- Async*異步類型鉤子
- Parallel
- Series
由淺入深學習Tapable
webpack有兩個非常重要的類:Compiler和Compilation。他們通過注入插件的方式,來監聽webpack的所有生命周期,插件的注入離不開各種各樣的Hook,而他們的Hook是如何得到的呢?其實是創建了Tapable庫中各種Hook的實例。
Tapable是什么
Tapable是一個任務調度庫,它的核心思基于發布訂閱模式是將任務執行邏輯和調度邏輯分離,Tapable在webpack中用于plugin的管理,在可以實現復雜調度邏輯的同時盡可能保證可維護性。
Tapable的機制與Event類似,它可以用來定義各種各樣的鉤子,相當于Event中的事件注冊,但是與Event不同的是,Event中各個事件之間相互不關聯,互不影響,但是tapable注冊的事件之間可以是有關系的,這種關系通過Tapable定義的各個鉤子類來實現。其實,Tapable的核心就是這些鉤子類。因此,我們接下來的重點就是講述這些鉤子類,并實現它們。
Tapable的Hook分類
同步和異步的
- 以sync開頭的,是同步的Hook
- 以async開頭的,兩個事件處理回調,不會等待上一次處理回調結束后再執行下一次回調
使用
Tapable的每個子類都是一個用于注冊和觸發事件的鉤子,我們可以查看一下SyncHook實例身上有哪些屬性,找到它注冊事件和觸發事件的屬性。
SyncHook {_args: [],name: undefined,taps: [],interceptors: [],_call: [Function: CALL_DELEGATE],call: [Function: CALL_DELEGATE], // 用于觸發同步事件的鉤子_callAsync: [Function: CALL_ASYNC_DELEGATE],callAsync: [Function: CALL_ASYNC_DELEGATE], // 用于觸發異步事件的鉤子_promise: [Function: PROMISE_DELEGATE],promise: [Function: PROMISE_DELEGATE],_x: undefined,compile: [Function: COMPILE],tap: [Function: tap], // 用于注冊同步事件的鉤子tapAsync: [Function: TAP_ASYNC], // 用于注冊異步事件的鉤子tapPromise: [Function: TAP_PROMISE],constructor: [Function: SyncHook]
}
Sync*同步類型鉤子
基本使用
const { SyncHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hooks(webpack完成)syncHook: new SyncHook(["name", "age"]),};// 2. 用hooks監聽事件(自定義plugin)this.hooks.syncHook.tap("event1", (name, age) => {console.log("event1事件監聽執行了:", name, age);});this.hooks.syncHook.tap("event2", (name, age) => {console.log("event2事件監聽執行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 發出去事件(webpack完成)
compiler.hooks.syncHook.call("小張", 20);
結果:
bail
當有返回值時,就不會執行后續的事件觸發了
const { SyncBailHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hooksbailHook: new SyncBailHook(["name", "age"]),};// 2. 用hooks監聽事件(自定義plugin)this.hooks.bailHook.tap("event1", (name, age) => {console.log("event1事件監聽執行了:", name, age);return 123});this.hooks.bailHook.tap("event2", (name, age) => {console.log("event2事件監聽執行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 發出去事件
compiler.hooks.bailHook.call("小張", 20);
輸出結果:
Loop
當返回值為true,就會反復執行該事件,當返回值為undefined或者不返回內容,就退出事件
const { SyncLoopHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hooksloopHook: new SyncLoopHook(["name", "age"]),};let count = 0;// 2. 用hooks監聽事件(自定義plugin)this.hooks.loopHook.tap("event1", (name, age) => {if (count < 5) {console.log("event1事件監聽執行了:", name, age);count++;return true;} else {return;}});this.hooks.loopHook.tap("event2", (name, age) => {console.log("event2事件監聽執行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 發出去事件
compiler.hooks.loopHook.call("小張", 20);
輸出結果:
Waterfall
當返回值不為undefined時,會將這次返回的結果作為下次事件的第一個參數
const { SyncWaterfallHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hookswaterfallHook: new SyncWaterfallHook(["name", "age"]),};// 2. 用hooks監聽事件(自定義plugin)this.hooks.waterfallHook.tap("event1", (name, age) => {console.log("event1事件監聽執行了:", name, age);// return “小李”,小李作為下一個事件的第一個參數return "小李";});this.hooks.waterfallHook.tap("event2", (name, age) => {console.log("event2事件監聽執行了:", name, age);});}
}const compiler = new myCompiler();
// 3. 發出去事件
compiler.hooks.waterfallHook.call("小張", 20);
輸出結果:
Async*異步類型鉤子
Parallel
并行,不會等到上一個事件回調執行結束,才會執行下一次事件處理回調
const { AsyncParallelHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hooksparallelHook: new AsyncParallelHook(["name", "age"]),};// 2. 用hooks監聽事件(自定義plugin)this.hooks.parallelHook.tapAsync("event1", (name, age) => {setTimeout(() => {console.log("event1事件監聽執行了:", name, age);}, 3000);});this.hooks.parallelHook.tapAsync("event2", (name, age) => {setTimeout(() => {console.log("event2事件監聽執行了:", name, age);}, 3000);});}
}const compiler = new myCompiler();
// 3. 發出去事件
compiler.hooks.parallelHook.callAsync("小張", 20);
輸出結果:
Series
串行,會等待上一次異步的Hook,即按照注冊的順序依次執行
const { AsyncSeriesHook } = require("tapable");class myCompiler {constructor() {this.hooks = {// 1. 創建hooksseriesHook: new AsyncSeriesHook(["name", "age"]),};// 2. 用hooks監聽事件(自定義plugin)this.hooks.seriesHook.tapAsync("event1", (name, age, callback) => {console.log("event1事件監聽執行了:", name, age);// 這個callback決定下一個事件的執行callback();});this.hooks.seriesHook.tapAsync("event2", (name, age, callback) => {console.log("event2事件監聽執行了:", name, age);// 這個callback決定發出事件中的函數執行callback();});}
}const compiler = new myCompiler();
// 3. 發出去事件
// 第三個參數決定第一個事件的執行
compiler.hooks.seriesHook.callAsync("小張", 20, () => {console.log("所有事件都執行完成啦!");
});
輸出結果: