1. 程式人生 > >webpack tapable庫中的同步非同步鉤子

webpack tapable庫中的同步非同步鉤子

Webpack本質上是一種事件流的機制,它的工作流程就是將各個外掛串聯起來,實現這一切的核心就是Tapable

webpack中最核心的負責編譯的Compiler和負責建立bundle的Compilation都是Tapable的例項

compiler 物件是 webpack 的編譯器物件,webpack 的核心就是編譯器
compiler 物件會在啟動 webpack 的時候被一次性的初始化,
compiler 物件中包含了所有 webpack 可自定義操作的配置,
例如 loader 的配置,plugin 的配置,entry 的配置等各種原始 webpack 配置等,
在 webpack 外掛中的自定義子編譯流程中,我們肯定會用到 compiler 物件中的相關配置資訊,
我們相當於可以通過 compiler 物件拿到 webpack 的主環境所有的資訊。


compilation 物件負責生成編譯資源

compilation 例項繼承於 compiler,
compilation 物件代表了一次單一的版本 webpack 構建和生成編譯資源的過程。
當執行 webpack 開發環境中介軟體時,每當檢測到一個檔案變化,一次新的編譯將被建立,
從而生成一組新的編譯資源以及新的 compilation 物件。
一個 compilation 物件包含了 當前的模組資源、編譯生成資源、變化的檔案、以及 被跟蹤依賴的狀態資訊。
編譯物件也提供了很多關鍵點回調供外掛做自定義處理時選擇使用。

 

tapable 為webpack 中的核心庫  負責控制各外掛在 webpack 事件流上執行

tapable包暴露了許多Hook類,可用於為外掛建立鉤子

各鉤子的核心思想其實就是我們常見的訂閱釋出模式的一種應用

我們來看幾個hook的實現

SyncHook

class SyncHook{
	constructor(){
		this.hooks = [] //任務佇列
	}
	tap(name,fn){ //釋出者
		this.hooks.push(fn)
	}
	call(...arg){ //訂閱者
		this.hooks.forEach((item)=>item(...arg))
	}
}

let queue = new SyncHook(["name"]);
console.time("start")
queue.tapAsync("1",function(name,cb){
	setTimeout(function(){
		console.log(1,name);
		cb();
	},1000)
})
queue.tapAsync("2",function(name,cb){
	setTimeout(function(){
		console.log(2,name);
		cb();
	},2000)
})
queue.tapAsync("3",function(name,cb){
	setTimeout(function(){
		console.log(3,name);
		cb();
	},3000)
})
queue.callAsync("test",()=>{
   console.timeEnd("end")
})

 

AsyncSeriesHook

class AsyncSeriesHook{
	constructor(){
		this.hooks = []
	}
	tapAsync(name,fn){
		this.hooks.push(fn)
	}
	callAsync(...arg){
		let num = 0
		let done = arg[arg.length-1];
		let name = arg[0];
		let that = this;
		function next(){// 把當前函式傳給鉤子的回撥 遞迴呼叫 就是這個鉤子的核心 
			that.hooks[num]?that.hooks[num](name,next):done();
			num++;
		}
		next();
	}
}
let queue = new AsyncSeriesHook(["name"]);
console.time("start")
queue.tapAsync("1",function(name,cb){
	setTimeout(function(){
		console.log(1,name);
		cb();
	},1000)
})
queue.tapAsync("2",function(name,cb){
	setTimeout(function(){
		console.log(2,name);
		cb();
	},2000)
})
queue.tapAsync("3",function(name,cb){
	setTimeout(function(){
		console.log(3,name);
		cb();
	},3000)
})

queue.callAsync("test",()=>{
   console.timeEnd("start")
})

註冊鉤子:

const { Tapable ,SyncHook } = require("tapable");

let t = new Tapable();

t.hooks = {
	myhook:new SyncHook()
}

let called = 0;

t.hooks.myhook.tap("myhook",()=>called++);
t.hooks.myhook.call();

t.hooks.myhook.tap("myhook",()=>called+=10);
t.hooks.myhook.call();

console.log(called);