Tapable:实现发布订阅的一个库。在 Webpack 中广泛使用。
Github:Tapble
注:文章中使用的 version 为 2.2.1
README 介绍:The tapable package expose many Hook classes, which can be used to create hooks for plugins.
这个库暴露了各种类型的 Hook 的类,让我们使用。
1. SyncHook
最简单的一个同步 Hook:顺序执行 tap 进去的函数( tapped function )。
举个 🌰:从上到下 tap 了三个函数,执行的顺序也是按照 tap 的顺序。
/**
* @author: lxdll
* Tapable: SyncHook
*/
const { SyncHook } = require('tapable')
// 实例化 SyncHook
const syncHook = new SyncHook(['arg'])
// function1 -> tap
syncHook.tap('function1', (arg) => {
console.log('function1 arg: ', arg)
console.log('function1 call.')
console.log('---------------')
})
// function2 -> tap
syncHook.tap('function2', (arg) => {
console.log('function2 arg: ', arg)
console.log('function2 call.')
console.log('---------------')
})
// function3 -> tap
syncHook.tap('function3', (arg) => {
console.log('function3 arg: ', arg)
console.log('function3 call.')
console.log('---------------')
})
// SyncHook 调用
syncHook.call('I am arg.')
运行结果:
2. SyncBailHook
可以 提前终止 的同步 Hook:当有一个任意的 tapped function 返回了 non-undefined 的值,那么 SyncBailHook 会停止执行剩下的 tapped function。
Bail 效果,个人理解就是一个熔断的效果,即提前终止整个 call 的过程。
举个 🌰:在 function2 中,我们 return 了一个值,会触发 Bail 效果,导致不会触发 function2 后面的 function3。
/**
* @author: lxdll
* Tapable: SyncBailHook
*/
const { SyncBailHook } = require('tapable')
// 实例化 SyncBailHook
const syncBailHook = new SyncBailHook(['arg'])
// function1 -> tap
syncBailHook.tap('function1', (arg) => {
console.log('function1 arg: ', arg)
console.log('function1 call.')
console.log('---------------')
})
// function2 -> tap
syncBailHook.tap('function2', (arg) => {
console.log('function2 arg: ', arg)
console.log('function2 call.')
console.log('---------------')
return 'anything'
})
// function3 -> tap
syncBailHook.tap('function3', (arg) => {
console.log('function3 arg: ', arg)
console.log('function3 call.')
console.log('---------------')
})
// SyncBailHook 调用
syncBailHook.call('I am arg.')
运行结果:
注:直接写 return; / return undefined; 都不会触发 Bail 效果。
3. SyncLoopHook
可循环执行的同步 Hook:在顺序执行 tapped function 过程中,如果有任意一个 tapped function 返回了 non-undefined 的值,那么 SyncLoopHook 会 restart,从第一个 tapped function 重新开始执行,直到所有的 tapped function 都没有返回 non-undefined 的值。
举个 🌰:我们初始化时有一个 tappedFunction2Flag 为 false,在执行到 function2 时,我们触发 restart,并且将 flag 置为 true。
/**
* @author: lxdll
* Tapable: SyncLoopHook
*/
const { SyncLoopHook } = require('tapable')
// function2 的标识
let tappedFunction2Flag = false
// 实例化 SyncLoopHook
const syncLoopHook = new SyncLoopHook(['arg'])
// function1 -> tap
syncLoopHook.tap('function1', (arg) => {
console.log('function1 arg: ', arg)
console.log('function1 call.')
console.log('---------------')
})
// function2 -> tap
syncLoopHook.tap('function2', (arg) => {
console.log('function2 arg: ', arg)
console.log('function2 call.')
console.log('---------------')
// 第一次执行过来时,触发 Loop
// 并且将 flag 置为 true,之后就不会触发 Loop 了
if (!tappedFunction2Flag) {
tappedFunction2Flag = true
console.log('restart && loop.')
return 'non-undefined'
}
})
// function3 -> tap
syncLoopHook.tap('function3', (arg) => {
console.log('function3 arg: ', arg)
console.log('function3 call.')
console.log('---------------')
})
syncLoopHook.call('I am arg.')
运行结果:
4. SyncWaterfallHook
瀑布型同步 Hook:顺序执行 tapped function 时,当前执行的 tapped function 的入参是上一个 tapped function 的返回值。
注:如果恰好上一个 tapped function 没有返回值,那么取上上个的返回值。
/**
* @author: lxdll
* Tapable: SyncWaterfallHook
*/
const { SyncWaterfallHook } = require('tapable')
// 实例化 SyncWaterfallHook
const syncWaterfallHook = new SyncWaterfallHook(['arg'])
// function1 -> tap
syncWaterfallHook.tap('function1', (arg) => {
console.log('function1 arg: ', arg)
console.log('function1 call.')
console.log('---------------')
return 'function1 result.'
})
// function2 -> tap
syncWaterfallHook.tap('function2', (arg) => {
console.log('function2 arg: ', arg)
console.log('function2 call.')
console.log('---------------')
return 'function2 result.'
})
// function3 -> tap
syncWaterfallHook.tap('function3', (arg) => {
console.log('function3 arg: ', arg)
console.log('function3 call.')
console.log('---------------')
return 'function3 result.'
})
syncWaterfallHook.call('Init arg.')
运行结果: