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,

与上相同。

相关文章
相关标签/搜索