tapable介绍-同步钩子 SyncHook
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来。
而实现这一切的核心就是Tapable。
Tapable有点类似于nodejs的events库,核心原理也是依赖发布订阅模式。
查看webpack的源码,找到tapable
新建空白项目 webpack-tapable
初始化package.json
shell
yarn init -y
安装一下webpack、webpack-cli
shell
yarn add webpack@^4.32.2 webpack-cli@^3.3.2 -D
查看webpack-tapable\node_modules\webpack\lib\Compiler.js
,编译模块中的代码,就会发现tapable,这是它的主核心模块
js
// webpack-tapable\node_modules\webpack\lib\Compiler.js
const {
Tapable,
SyncHook,
SyncBailHook,
AsyncParallelHook,
AsyncSeriesHook
} = require("tapable");
// ...
class Compiler extends Tapable {
constructor(context) {
super();
this.hooks = {
/** @type {SyncBailHook<Compilation>} */
shouldEmit: new SyncBailHook(["compilation"]),
/** @type {AsyncSeriesHook<Stats>} */
done: new AsyncSeriesHook(["stats"]),
/** @type {AsyncSeriesHook<>} */
additionalPass: new AsyncSeriesHook([]),
/** @type {AsyncSeriesHook<Compiler>} */
beforeRun: new AsyncSeriesHook(["compiler"]),
/** @type {AsyncSeriesHook<Compiler>} */
run: new AsyncSeriesHook(["compiler"]),
/** @type {AsyncSeriesHook<Compilation>} */
emit: new AsyncSeriesHook(["compilation"]),
/** @type {AsyncSeriesHook<string, Buffer>} */
assetEmitted: new AsyncSeriesHook(["file", "content"]),
/** @type {AsyncSeriesHook<Compilation>} */
afterEmit: new AsyncSeriesHook(["compilation"]),
}
}
// ...
}
里面有各种钩子。
插件里包含着异步钩子方法和同步钩子方法。
一个小例子,学习tapable
安装一下tapable
shell
yarn add tapable@^1.1.3
同步钩子 SyncHook
新建文件
js
// webpack\webpack-tapable\1.start.js
// 同步钩子SyncHook tapable
let { SyncHook } = require('tapable')
class Lesson {
// new 对象时 构造函数会被执行
constructor() {
// new对象的时候 注册一些钩子
// 一旦new一个新的实例时,这些钩子就被启用了
this.hook = {
// 假如有个架构课
arch: new SyncHook(['name']), // 可能会传一个参数,参数是可选的
}
}
// 用来注册的方法
tap() { // 注册监听函数
this.hook.arch.tap('vue', function (name) {
console.log('vue 111', name);
}) // 拿到钩子实例,实例上就有一个tap方法
this.hook.arch.tap('react', function (name) {
console.log('react 111', name);
})
// 001 调用这个方法时,会将上面两个事件注册到数组中
}
// 启动钩子的方法
start() {
// 执行之前注册的事件
this.hook.arch.call('cheny') // 实例上有一个call 方法,执行注册的事件
// 002 调用这个方法时,会让数组中注册的方法依次执行
}
}
// 测试
let l = new Lesson() // 声明一个实例
// 注册两个事件
l.tap()
// 调用start方法 启动钩子
l.start()
执行结果
实际就是一个发布订阅,例子中模拟的是,假如有一个架构课,上架构课之前先把课程准备好。也即先注册事件。
然后等到时机成熟了,然后再依次执行之前注册好的事件。
自己手动实现一下同步钩子 SyncHook
新建文件
js
// webpack\webpack-tapable\1.case.js
class SyncHook { // 同步钩子
constructor(args) { // args -> ['name']
this.tasks = [] // 保存注册的事件
}
// 同步注册事件
tap(name, task) {
this.tasks.push(task)
}
// 按顺序依次执行注册过的事件
call(...args) {
// console.log(this.tasks);
this.tasks.forEach((task) => {
task(...args)
})
}
}
let hook = new SyncHook(['name']) // 参数可以传可以不传
// 注册事件
hook.tap('vue', function (name) {
console.log('vue 1111', name);
})
hook.tap('react', function (name) {
console.log('react 1111', name);
})
// 依次执行
hook.call('cheny')
总结
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来。
而实现这一切的核心就是Tapable。
核心原理依赖发布订阅模式。
注册事件,然后在合适的时机执行事件,各个插件就是通过这样的机制执行的。
本节学习了tapable的同步钩子 SyncHook,同步注册事件,然后依次顺序执行
jsclass Lesson { // new 对象时 构造函数会被执行 constructor() { // new对象的时候 注册一些钩子 // 一旦new一个新的实例时,这些钩子就被启用了 this.hook = { // 假如有个架构课 arch: new SyncHook(['name']), // 可能会传一个参数,参数是可选的 } } // 用来注册的方法 tap() { // 注册监听函数 this.hook.arch.tap('vue', function (name) { console.log('vue 111', name); }) // 拿到钩子实例,实例上就有一个tap方法 this.hook.arch.tap('react', function (name) { console.log('react 111', name); }) // 001 调用这个方法时,会将上面两个事件注册到数组中 } // 启动钩子的方法 start() { // 执行之前注册的事件 this.hook.arch.call('cheny') // 实例上有一个call 方法,执行注册的事件 // 002 调用这个方法时,会让数组中注册的方法依次执行 } } // 测试 let l = new Lesson() // 声明一个实例 // 注册两个事件 l.tap() // 调用start方法 启动钩子 l.start()
然后自己仿写了一下,核心就是将事件保存到一个数组中,然后再依次执行。
jsclass SyncHook { // 同步钩子 constructor(args) { // args -> ['name'] this.tasks = [] // 保存注册的事件 } // 同步注册事件 tap(name, task) { this.tasks.push(task) } // 按顺序依次执行注册过的事件 call(...args) { // console.log(this.tasks); this.tasks.forEach((task) => { task(...args) }) } } let hook = new SyncHook(['name']) // 参数可以传可以不传 // 注册事件 hook.tap('vue', function (name) { console.log('vue 1111', name); }) hook.tap('react', function (name) { console.log('react 1111', name); }) // 依次执行 hook.call('cheny')
参考
https://www.bilibili.com/video/BV1a4411e7Bz?p=28&spm_id_from=pageDriver