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');