這是我參與8月更文挑戰的第7天,活動詳情查看:8月更文挑戰webpack
Webpack 本質上是一種事件流的機制,它的工做流程就是將各個插件串聯起來,而實現這一切的核心就是 tapable
,Webpack 中最核心的,負責編譯的 Compiler
和負責建立 bundles
的 Compilation
都是 tapable
構造函數的實例。git
Tapable就是webpack用來建立鉤子
的庫
。 Tapable
是webpack內部使用的一個流程管理工具,主要用來串聯插件,完善事件流執行。github
簡單來講,Tapable
就是webpack用來建立鉤子
的,那麼爲何webapck要建立鉤子呢?咱們先看下面一句話:web
webpack的核心功能是經過抽離出不少
插件
來實現的。能夠說插件就是webpack的基石,這些基石又影響着流程的走向。這些鉤子是經過Tapable
串起來的,能夠類比Vue框架的生命週期,webpack也有本身的生命週期,在週期裏邊會順序地觸發一些鉤子,掛載在這些鉤子上的插件的方法
得以執行,從而進行一些特定的邏輯處理。在插件裏邊,構建的實體或構建出來的數據結果都是可觸達的,這樣作實現了webpack的高度可擴展。promise
咱們先簡單理解一下插件,插件
就是功能的擴展,不會影響原有的數據。markdown
在webpack整個運行流程中,咱們須要不少插件放在特定的時期去擴展咱們想要的功能。插件是如何實現本身代碼的功能呢?就是經過在webpack的各類鉤子
函數上掛載
本身的方法
。webapck運行時會本身執行
鉤子上掛載的這些插件的方法。因此,webapck須要在運行的各個時期暴露
出鉤子
,好讓插件在這些鉤子上掛載他們要執行的方法。webapck的鉤子都是經過Tapable
建立的。框架
咱們能夠把webpack實例理解爲一個長的衣櫃
,從上到下表明着webpack運行期間不一樣的流程。webpack從上到下建立了不一樣時期的衣架(鉤子),有掛鞋的,掛衣服的,掛褲子的,那麼咱們就能夠在這些鉤子上掛載咱們想要掛載的東西(插件的各類方法)。異步
Tapable 中主要提供了同步
與異步
兩種鉤子。async
同步鉤子:函數
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
複製代碼
異步鉤子:
異步並行鉤子:
AsyncParallelHook,
AsyncParallelBailHook,
複製代碼
異步串行鉤子:
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook,
複製代碼
同步鉤子的使用:
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
複製代碼
SyncHook:
// 同步鉤子
const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
} = require ('tapable');
// 初始化hook,肯定參數
const syncHK = new SyncHook(['name', 'age'])
// 生產商品,註冊事件
syncHK.tap( 'plugin1', (name, age)=> {
console.log('plugin1:', name, age);
} )
syncHK.tap('plugin2:', (name, age) => {
console.log('plugin2:', name, age);
})
// 消費
syncHK.call('zack', 18)
複製代碼
SyncBailHook:
const bailHook = new SyncBailHook(['name', 'age'])
// 註冊事件
bailHook.tap('a', (name, age) => {
console.log('a:', name, age);
})
bailHook.tap('b', (name, age) => {
console.log('b:', name, age);
return 'b'
})
bailHook.tap('c', (name, age) => {
console.log('c:', name, age);
})
// 消費
bailHook.call('lili', 20)
// result2
// a: lili 20
// b: lili 20
複製代碼
SyncWaterfallHook:
const waterFallHK = new SyncWaterfallHook(['name', 'age'])
// 註冊事件
waterFallHK.tap('one', (name, age) => {
console.log('one:', name, age);
return age
})
waterFallHK.tap('two', (age) => {
console.log('two:', age);
})
// 消費
waterFallHK.call('pilipili', 25)
// result3
// one: pilipili 25
// two: 25
複製代碼
SyncLoopHook:
let num = 20
const loopHK = new SyncLoopHook (['name', 'age'])
// 生產商品
loopHK.tap('1', (name, age) => {
console.log('1:', name, age);
if(num>18) {
num--;
console.log('num:', num);
return num
}
})
loopHK.tap('2', (name, age) => {
console.log('2', name, age);
})
// 消費
loopHK.call('kiki', 21)
// result4:
// 1: kiki 21
// num: 19
// 1: kiki 21
// num: 18
// 1: kiki 21
// 2 kiki 21
複製代碼
異步並行鉤子的使用:
異步鉤子註冊通常不使用tap,否則最後仍是會串行,使用後兩種。
全部任務一塊兒執行,誰先完成誰先輸出,全部任務執行完後執行回調。
AsyncParallelHook,
AsyncParallelBailHook,
複製代碼
AsyncParallelHook:
異步並行執行,當全部註冊事件都執行完成後,才執行callAsync
或者promise
。
const asyncPHK = new AsyncParallelHook(['name'])
asyncPHK.tapAsync('print1', (name, callbackName) => {
setTimeout(() => {
console.log('1', name);
callbackName('hhhh', '11')
}, 2000)
})
asyncPHK.callAsync('lili', (err, res) => {
console.log('err', err);
console.log('res', res);
})
// 1 lili
// err hhhh
// res undefined
複製代碼
const asyncPHK2 = new AsyncParallelHook(['name'])
asyncPHK2.tapPromise('1', (name) => {
// tapPromise須要返回一個Promise
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(name, 1);
resolve('11')
}, 2000)
})
})
asyncPHK2.tapPromise('2', (name) => {
// tapPromise須要返回一個Promise
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(name, 2);
resolve('22')
}, 1000)
})
})
// 觸發
asyncPHK2.promise('tapPromise')
.then(res => {
console.log('over', res);
})
.catch(err => {
console.log('error', err);
})
// tapPromise 2
// tapPromise 1
// over undefined
複製代碼
AsyncParallelBailHook:
const asyncPBailHK = new AsyncParallelBailHook(['name'])
asyncPBailHK.tapAsync('1', (name, callBK) => {
setTimeout(() => {
console.log(name, 01);
callBK('001')
}, 2000)
})
asyncPBailHK.tapAsync('2', (name, callBK) => {
setTimeout(() => {
console.log(name, 02);
callBK('002')
}, 1000)
})
asyncPBailHK.callAsync('bail', (res) => {
console.log(res);
})
// bail 2
// bail 1
// 001
複製代碼
const asyncPBailHK2 = new AsyncParallelBailHook(['name'])
asyncPBailHK2.tapPromise('2', (name) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(name, 22);
resolve('222')
}, 2000)
})
})
asyncPBailHK2.tapPromise('2', (name) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(name, 23);
resolve('223')
}, 1000)
})
})
asyncPBailHK2.promise('bail222')
.then(res => {
console.log('over', res);
})
.catch(err => {
console.log('err', err);
})
複製代碼
異步串行鉤子的使用:
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook,
與上相同。