tapable事件流插件

tapable

Webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的Compiler和负责创建bundle的Compilation都是Tapable的实例

image

const {
    SyncHook,
    SyncBailHook,
    SyncWaterfallHook,
    SyncLoopHook,
    AsyncParallelHook,
    AsyncParallelBailHook,
    AsyncSeriesHook,
    AsyncSeriesBailHook,
    AsyncSeriesWaterfallHook
 } = require("tapable");

SyncHook

串行同步执行,不关心返回值

//钩子可以在stage和其他钩子之间穿插钩子
const hook = new SyncHook()
const calls = [];

hook.tap("A",() => calls.push("A"))
hook.tap({
	name:"B",
	before:"A"
},() => calls.push("B"))

calls.length = 0
hook.call()


hook.tap({
	name:"C",
	before:["A","B"]
},() => calls.push("C"))

calls.length = 0
hook.call()


hook.tap({
	name:"D",
	before:"B"
},() => calls.push("D"))

calls.length = 0;
hook.call()

hook.tap({
	name:"E",
	stage:3
},() => calls.push("E"))

hook.tap({
	name:"F",
	stage:1
},() => calls.push("F"))

calls.length = 0;
hook.call()


console.log(calls)


//创建同步钩子
const h0 = new SyncHook(["arg1"]);

h0.tap("A",(name) => {
	console.log(name)
})

h0.tap("B",(name) => {
	console.log(name)
})

h0.call('plus',24)


SyncBailHook

串行同步执行,有一个返回值不为null则跳过剩下的逻辑

const h1 = new SyncBailHook(["a"]);

h1.tap("A",a => {console.log(a) ;return a})
h1.tap("B",a => console.log(a))
h1.call(1)

SyncWaterfallHook

const h1 = new SyncWaterfallHook(['name'])

h1.tap("A",(name) => {
	console.log(name,1)
})
h1.tap("B",(data) => {
	console.log(data,2)
	return 2
})
h1.tap("C",(data) => {
	console.log(data,3)
	return 3
})

h1.call('plus',24)

SyncLoopHook

监听函数返回true表示继续循环,返回undefine表示结束循环

const h1 = new SyncLoopHook(['name'])

let count = 0
h1.tap('A',name => (
	count < 3 ?
	(count++,console.log(name),true)
	:undefined
))

h1.call(
	'plus'
)

AsyncParallelHook

异步并行钩子

const h1 = new AsyncParallelHook(['name'])

h1.tap('A',() => console.log(1))
h1.tap('B',() => console.log(2))
h1.tap('C',() => console.log(3))

h1.callAsync('test',err => {
	console.log(err)
})
const h1 = new AsyncParallelHook(['name'])

console.time('count')
h1.tapAsync('A',(name,callback) => {
	setTimeout(() => (console.log(1),callback()),2000)
})
h1.tapAsync('B',(name,callback) => {
	setTimeout(() => (console.log(2),callback()),1000)
})
h1.tapAsync('C',(name,callback) => {
	setTimeout(() => (console.log(3),callback()),3000)
})

h1.callAsync('test',err => {
	console.log(err)
	console.timeEnd('count')
})
const h1 = new AsyncParallelHook(['name'])

console.time('count')
h1.tapPromise('A',(name,callback) => (
	 new Promise((resolve,reject) => {
		setTimeout(() => (console.log(1),resolve()),2000)
	})
))

h1.tapPromise('B',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(2),resolve()),1000)
	})
))

h1.tapPromise('C',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(3),resolve()),3000)
	})
))

h1.callAsync('test',err => {
	console.log(err)
	console.timeEnd('count')
})

AsyncParallelBailHook

带保险带异步执行钩子

let h1=new AsyncParallelBailHook(['name']);
console.time('count');
h1.tap('A',function(name){
    console.log(1);
    return "Wrong";
});
h1.tap('B',function(name){
    console.log(2);
});
h1.tap('C',function(name){
    console.log(3);
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('count');
});
let h1=new AsyncParallelBailHook(['name']);
console.time('count');
h1.tapAsync('A',function(name,callback){
    console.log(1);
    return "Wrong";
});
h1.tapAsync('B',function(name,callback){
    console.log(2);
});
h1.tapAsync('C',function(name.callback){
    console.log(3);
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('count');
});
const h1 = new AsyncParallelBailHook(['name'])

console.time('count')
h1.tapPromise('A',(name,callback) => (
	 new Promise((resolve,reject) => {
		setTimeout(() => (console.log(1),resolve()),2000)
	})
))

h1.tapPromise('B',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(2),resolve()),1000)
	})
))

h1.tapPromise('C',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(3),resolve()),3000)
	})
))

h1.callAsync('test',err => {
	console.log(err)
	console.timeEnd('count')
})

AsyncSeriesHook

异步串行钩子

let h1 = new AsyncSeriesHook(['name']);
console.time('cost');
h1.tap('A',function(name){
    console.log(1);
});
h1.tap('B',function(name){
    console.log(2);
});
h1.tap('C',function(name){
    console.log(3);
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('cost');
});
let h1 = new AsyncSeriesHook(['name']);
console.time('cost');
h1.tapAsync('A',function(name,callback){
    setTimeout(function(){
	   console.log(1);
	   callback()
   },1000)
});
h1.tapAsync('B',function(name,callback){
    setTimeout(function(){
	   console.log(2);
	   callback()
   },2000)
});
h1.tapAsync('C',function(name,callback){
    setTimeout(function(){
	   console.log(3);
	   callback()
   },3000)
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('cost');
});
let h1=new AsyncSeriesHook(['name']);
console.time('cost');
h1.tapPromise('A',function(name){
   return new Promise(function(resolve){
       setTimeout(function(){
           console.log(1);
           resolve();
       },1000)
   });
});
h1.tapPromise('B',function(name,callback){
    return new Promise(function(resolve){
        setTimeout(function(){
            console.log(2);
            resolve();
        },2000)
    });
});
h1.tapPromise('C',function(name,callback){
    return new Promise(function(resolve){
        setTimeout(function(){
            console.log(3);
            resolve();
        },3000)
    });
});
h1.promise('test').then(data=>{
    console.log(data);
    console.timeEnd('cost');
});

AsyncSeriesBailHook

let h1 = new AsyncSeriesBailHook(['name']);
console.time('cost');
h1.tap('A',function(name){
    console.log(1);
    return "Wrong";
});
h1.tap('B',function(name){
    console.log(2);
});
h1.tap('C',function(name){
    console.log(3);
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('cost');
});
let h1 = new AsyncSeriesBailHook(['name']);
console.time('cost');
h1.tapAsync('A',function(name,callback){
    setTimeout(function(){
	   console.log(1);
	   callback('wrong')
   },1000)
});
h1.tapAsync('B',function(name,callback){
    setTimeout(function(){
	   console.log(2);
	   callback()
   },2000)
});
h1.tapAsync('C',function(name,callback){
    setTimeout(function(){
	   console.log(3);
	   callback()
   },3000)
});
h1.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('cost');
});
const h1 = new AsyncSeriesBailHook(['name'])

console.time('count')
h1.tapPromise('A',(name,callback) => (
	 new Promise((resolve,reject) => {
		setTimeout(() => (console.log(1),reject()),2000)
	})
))

h1.tapPromise('B',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(2),resolve()),1000)
	})
))

h1.tapPromise('C',(name,callback) => (
	new Promise((resolve,reject) => {
		setTimeout(() => (console.log(3),resolve()),3000)
	})
))

h1.promise('test',err => {
	console.log(err)
	console.timeEnd('count')
},err => {
   console.log(err);
    console.timeEnd('cost');
})

AsyncSeriesWaterfallHook

let {AsyncSeriesWaterfallHook} = require('tapable');
let h1 = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
h1.tap('1',function(name,callback){
    console.log(1);
});
h1.tap('2',function(data){
    console.log(2,data);
});
h1.tap('3',function(data){
    console.log(3,data);
});
queue.callAsync('test',err=>{
    console.log(err);
    console.timeEnd('cost');
});
let h1 = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
h1.tapAsync('1',function(name,callback){
   setTimeout(function(){
       console.log(1);
       callback(null,1);
   },1000)
});
h1.tapAsync('2',function(data,callback){
    setTimeout(function(){
        console.log(2);
        callback(null,2);
    },2000)
});
h1.tapAsync('3',function(data,callback){
    setTimeout(function(){
        console.log(3);
        callback(null,3);
    },3000)
});
h1.callAsync('test',(err,data)=>{
    console.log(err,data);
    console.timeEnd('cost');
});
let h1 = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
h1.tapPromise('1', function (name) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(name, 1);
            resolve(1);
        }, 1000);
    });
});
h1.tapPromise('2', function (data) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(data, 2);
            resolve(2);
        }, 2000);
    });
});
h1.tapPromise('3', function (data) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            console.log(data, 3);
            resolve(3);
        }, 3000);
    });
});
h1.promise('test').then(err => {
    console.timeEnd('cost');
});

tapable

class MyPlugin {
	constructor(){
		this.hooks = {
			add:new SyncHook(['name'])
		}
	}
}
const myPlugin = new MyPlugin()

myPlugin.hooks.add.tap('add',(name) => {
	console.log(name)
})

myPlugin.hooks.add.tap('minus',(name) => {
	console.log(name)
})
myPlugin.hooks.add.call('plus')
原文地址:https://www.cnblogs.com/pluslius/p/10219685.html