tapable
webpack本质上是一种事件流的机制,他的工作流程就是将各个插件串联起来,而实现这一切的核心就是tapable,
tapable有点类似于nodejs的events库,核心原理也是依赖于发布订阅模式:
继承了很多插件,同步的和异步的
tapable库中有3中注册方法 tap(同步注册)、tabAsync(回调cb)、tabPromise(注册是promise)
调用的三种方法 call、 callAsync、 promise
SyncHook
作用: 让添加的钩子按顺序执行
使用方式:
let {SyncHook} = require('tapable');
class Lesson {
constructor() {
this.hooks = {
arch: new SyncHook(['name']),
}
}
// 注册监听函数
tap() {
this.hooks.arch.tap('node', function(name) {
console.log('node', name);
});
this.hooks.arch.tap('react', function(name) {
console.log('react', name);
});
}
start() {
this.hooks.arch.call('zhangfeng');
}
}
let les = new Lesson();
les.tap(); // 注册这两个事件
les.start(); // 启动钩子
实现原理:
class SyncHook { // 钩子是同步的
constructor(args) { // args => ['name']
this.tasks = [];
}
call(...args) {
this.tasks.forEach(task => task(...args));
}
tap(name, task) {
this.tasks.push(task);
}
}
let hook = new SyncHook(['name']);
hook.tap('react', function (name) {
console.log('react', name);
});
hook.tap('node', function(name) {
console.log('node', name);
})
hook.call('zhangfeng');
SyncBail
作用: 如果有一个钩子返回的不是undefined,则不再往下执行;
使用方式:
let {SyncBailHook} = require('tapable');
class Lesson {
constructor() {
this.hooks = {
arch: new SyncBailHook(['name']),
}
}
// 注册监听函数
tap() {
this.hooks.arch.tap('node', function(name) {
console.log('node', name);
return 'node还需要加强学习'
});
this.hooks.arch.tap('react', function(name) {
console.log('react', name);
});
}
start() {
this.hooks.arch.call('zhangfeng');
}
}
let les = new Lesson();
les.tap(); // 注册这两个事件
les.start(); // 启动钩子
实现原理:
class SyncBailHook { // 钩子是同步的
constructor(args) { // args => ['name']
this.tasks = [];
}
call(...args) {
// this.tasks.forEach(task => task(...args));
let ret; // 这个函数的返回值
let index = 0; // 当前要先执行第一个
do {
ret = this.tasks[index++](...args);
}while (ret === undefined && index < this.tasks.length);
}
tap(name, task) {
this.tasks.push(task);
}
}
let hook = new SyncBailHook(['name']);
hook.tap('react', function (name) {
console.log('react', name);
return '到此为止'
});
hook.tap('node', function(name) {
console.log('node', name);
});
hook.call('zhangfeng');
SyncWaterfallHook
作用: 将上一个钩子的返回值,作为下一个钩子的参数
使用方法:
let {SyncWaterfallHook} = require('tapable');
// waterfall 瀑布
class Lesson {
constructor() {
this.hooks = {
arch: new SyncWaterfallHook(['name']),
}
}
// 注册监听函数
tap() {
this.hooks.arch.tap('node', function(name) {
console.log('node', name);
return 'node还需要加强学习'
});
this.hooks.arch.tap('react', function(data) {
console.log('react', data);
});
}
start() {
this.hooks.arch.call('zhangfeng');
}
}
let les = new Lesson();
les.tap(); // 注册这两个事件
les.start(); // 启动钩子
实现原理:
class SyncWaterfallHook { // 钩子是同步的
constructor(args) { // args => ['name']
this.tasks = [];
}
call(...args) {
let [first, ...others] = this.tasks;
let ret = first(...args);
others.reduce((a, b) => {
return b(a);
}, ret);
}
tap(name, task) {
this.tasks.push(task);
}
}
let hook = new SyncWaterfallHook(['name']);
hook.tap('react', function (name) {
console.log('react', name);
return '到此为止'
});
hook.tap('node', function(data) {
console.log('node', data);
});
hook.call('zhangfeng');
SyncLoopHook
作用:如果一个钩子返回不是undefined,则继续执行该钩子
使用方法:
let {SyncLoopHook} = require('tapable');
// 遇到某个不返回undefined的监听函数,会多次执行
class Lesson {
constructor() {
this.index = 0;
this.hooks = {
arch: new SyncLoopHook(['name']),
}
}
// 注册监听函数
tap() {
this.hooks.arch.tap('node', (name) => {
console.log('node', name);
return ++this.index === 3 ? undefined : 'node还需要加强学习';
});
this.hooks.arch.tap('react', (name) => {
console.log('react', name);
});
}
start() {
this.hooks.arch.call('zhangfeng');
}
}
let les = new Lesson();
les.tap(); // 注册这两个事件
les.start(); // 启动钩子
实现原理:
class SyncLoopHook { // 钩子是同步的
constructor(args) { // args => ['name']
this.tasks = [];
}
call(...args) {
this.tasks.forEach(task => {
let ret;
do {
ret = task(...args);
} while (ret!==undefined);
})
}
tap(name, task) {
this.tasks.push(task);
}
}
let hook = new SyncLoopHook(['name']);
let total = 0;
hook.tap('react', function (name) {
console.log('react', name);
return ++total === 3 ? undefined : '继续学习react';
});
hook.tap('node', function(name) {
console.log('node', name);
});
hook.call('zhangfeng');