webapck核心依賴庫--Tapable

這是我參與8月更文挑戰的第7天,活動詳情查看:8月更文挑戰webpack

small449948afb2499091509abb6a4438d23d1621960600.jpg

引言

Webpack 本質上是一種事件流的機制,它的工做流程就是將各個插件串聯起來,而實現這一切的核心就是 tapable,Webpack 中最核心的,負責編譯的 Compiler 和負責建立 bundlesCompilation 都是 tapable 構造函數的實例。git

1. 什麼是Tapable

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從上到下建立了不一樣時期的衣架(鉤子),有掛鞋的,掛衣服的,掛褲子的,那麼咱們就能夠在這些鉤子上掛載咱們想要掛載的東西(插件的各類方法)。異步

2. Tapable的基本概念

Tapable 中主要提供了同步異步兩種鉤子。async

同步鉤子:函數

SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
複製代碼

異步鉤子:

  • 異步並行鉤子:

    AsyncParallelHook,
    AsyncParallelBailHook,
    複製代碼
  • 異步串行鉤子:

    AsyncSeriesHook,
     AsyncSeriesBailHook,
     AsyncSeriesWaterfallHook,
    複製代碼

hook類型解析

  • 基本的鉤子(沒有Bail/Waterfall/Loop):只會簡單的調用每一個tap傳進去的函數。
  • 帶Waterfall的鉤子(瀑布流):也會調用每一個tap傳進去的函數,但會把每個函數的返回值傳給下一個函數參數。
  • 帶Bail的鉤子(保釋):容許更早的退出。若是有某個函數返回值不是undefined, bail類會中止執行後面其餘的函數執行,(保釋出來了)。
  • 帶Loop的鉤子:若是某個函數的返回值不是undefined,這循環(重複)調用這個回調函數,直到它的返回值爲undefined。

插件3種註冊方式

  1. tap: 生產同步鉤子對應的(事件)goods。
  2. tapAsync: 生產帶callback回調的異步鉤子對應的goods。
  3. tapPromise: 生產帶promise回調的異步鉤子對應的goods。

與註冊對應的3種調用方式

  1. call : 調用註冊的同步鉤子。
  2. callAsync: 調用註冊的有callback回調函數的異步鉤子。
  3. promise: 調用註冊的有promise回調的異步鉤子。

3. Tapable的基本使用示例

同步鉤子的使用

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,

與上相同。

相關文章
相關標籤/搜索