作者:粉爱_粉爱陈小翔 | 来源:互联网 | 2023-09-06 10:04
const{SyncHook,SyncBailHook,SyncWaterfallHook,SyncLoopHook,AsyncParallelHook,AsyncParallel
const {SyncHook,SyncBailHook,SyncWaterfallHook,SyncLoopHook,AsyncParallelHook,AsyncParallelBailHook,AsyncSeriesHook,AsyncSeriesBailHook,AsyncSeriesWaterfallHook} = require("tapable");
用法
All Hook constructors take one optional argument, which is a list of argument names as strings.
class Car {constructor() {this.hooks = {accelerate: new SyncHook(["newSpeed"]),brake: new SyncHook(),calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"])}}
}const muCar = new Car()
myCar.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));
myCar.hooks.brake.tap("WarningLampPlugin", () => warningLamp.on());
myCar.hooks.calculateRoutes.tapPromise("GoogleMapsPlugin", (source, target, routesList) => {return google.maps.findRoute(source, target).then(route => {routesList.add(route);});
});
钩子注册(钩入)方式
- 同步
- 异步
Hooks type
每个钩子都能监听一个或多个函数,函数如何执行取决于钩子的类型
- hook 基础钩子
- bail hook 只要有一个handler有返回值,剩下handler不执行
- waterfall hook 上一个handler的返回值当做下一个handler的入参
- loop hook 循环 只要钩子有返回值,不停loop
- sync hook 同步
- async hook 异步
- Async series 异步串行
- Async parallel 异步并行
拦截器
每个钩子都有拦截器,每个拦截器接收call,tap,register,loop,context五个属性
const {SyncLoopHook,
} = require("../lib/index")class Test {constructor(){this.hooks = {test: new SyncLoopHook(["name"]),};}
}const objTest = new Test()
objTest.hooks.test.intercept({call: (name) => {console.log("call");},tap: (Tap) => {console.log("tap");},loop: (name)=>{console.log('loop');},register: (Tap) => {console.log("register");},
});
objTest.hooks.test.tap('testPlugin',(name)=>{console.log(name);
})
objTest.hooks.test.call('test')
register
call
loop
tap
test
interface Tap {name: string,type: stringfn: Function,stage: number,context: boolean,before?: string | Array
}
webpack中如何使用Tapable
-
hooks均继承自hook(lib/Hook.js)
-
Tap tapAsync tappromise会把handler丢入到数组中。
-
call callAsync promise会按照相应的顺序去执行数组中的handler
lass SyncHookCodeFactory extends HookCodeFactory {content({ onError, onDone, rethrowIfPossible }) {return this.callTapsSeries({onError: (i, err) => onError(err),onDone,rethrowIfPossible});}
}const factory = new SyncHookCodeFactory();
const COMPILE = function(options) {factory.setup(this, options);return factory.create(options);
};
-
call
、callAsync
、promise
最终会调用每个hook的COMPILE
方法
-
COMPILE方法会实例化继承自HookCodeFactory的相应类并调用HookCodeFactory的create方法
-
create
方法用new Function(‘a’,‘b’,‘return a+b’)方式去创建每个handler的执行函数字符串
问:为啥用new Function去创建函数?
答:函数入参和函数体会根据入参的长度而动态生成,这样你可以根据实际情况来控制传入参数的个数,并且函数也只处理这几个入参。
参考
- Tapable readme
- 掘金-雾豹-深入源码解析 tapable 实现原理