tapable
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的Compiler和负责创建bundles的Compilation都是Tapable的实例
#
2.tapable用法const {
SyncHook,
SyncBailHook,
SyncWaterfallHook,
SyncLoopHook,
AsyncParallelHook,
AsyncParallelBailHook,
AsyncSeriesHook,
AsyncSeriesBailHook,
AsyncSeriesWaterfallHook
} = require("tapable");
3.Sync*类型的钩子
注册在该钩子下面的插件的执行顺序都是顺序执行。
只能使用
tap
注册,不能使用tapPromise
和tapAsync
注册3.1 SyncHook [#](#t33.1 SyncHook)
串行同步执行,不关心返回值
//let {SyncHook}=require('tapable'); class SyncHook{ constructor() { this.tasks=[]; } tap(name,task) { this.tasks.push(task); } call() { this.tasks.forEach(task=>task(...arguments)); } } let queue = new SyncHook(['name']); queue.tap('1',function(name){ console.log(name,1); }); queue.tap('2',function(name){ console.log(name,2); }); queue.tap('3',function(name){ console.log(name,3); }); queue.call('zxmf');
3.2 SyncBailHook [#](#t43.2 SyncBailHook)
串行同步执行,有一个返回值不为null则跳过剩下的逻辑
//let {SyncBailHook}=require('tapable'); class SyncBailHook{ constructor() { this.tasks=[]; } tap(name,task) { this.tasks.push(task); } call() { // for (let i=0;i<this.tasks.length;i++){ // let ret=this.tasks[i](...arguments); // if (ret) // break; // } let i=0,ret; do { ret=this.tasks[i++](...arguments); } while (!ret); } } let queue = new SyncBailHook(['name']); queue.tap('1',function(name){ console.log(name,1); return 'Wrong'; }); queue.tap('2',function(name){ console.log(name,2); }); queue.tap('3',function(name){ console.log(name,3); }); queue.call('zxmf');
3.3 SyncWaterfallHook [#](#t53.3 SyncWaterfallHook)
class SyncWaterfallHook{
constructor() {
this.tasks=[];
}
tap(name,task) {
this.tasks.push(task);
}
call() {
let [first,...tasks]=this.tasks;
tasks.reduce((ret,task)=>task(ret),first(...arguments));
}
}
let queue = new SyncWaterfallHook(['name']);
queue.tap('1',function(name,age){
console.log(name,age,1);
return 1;
});
queue.tap('2',function(data){
console.log(data,2);
return 2;
});
queue.tap('3',function(data){
console.log(data,3);
});
queue.call('zxmf',9);
3.4 SyncLoopHook [#](#t63.4 SyncLoopHook)
监听函数返回true表示继续循环,返回undefine表示结束循环
//let {SyncHook}=require('tapable');
class SyncLoopHook{
constructor() {
this.tasks=[];
}
tap(name,task) {
this.tasks.push(task);
}
call(...args) {
this.tasks.forEach(task => {
let ret=true;
do {
ret = task(...args);
}while(ret)
});
}
}
let queue = new SyncLoopHook(['name']);
let count = 0;
queue.tap('1',function(name){
console.log(count++);
if(count==3){
return;
}else{
return true;
}
});
queue.call('zxmf');
4. Async*类型的钩子
- 支持tap、tapPromise、tapAsync注册
- 每次都是调用tap、tapSync、tapPromise注册不同类型的插件钩子,通过调用call、callAsync 、promise方式调用。其实调用的时候为了按照一定的执行策略执行,调用compile方法快速编译出一个方法来执行这些插件。
4.1 AsyncParallel [#](#t84.1 AsyncParallel)
4.1.1 AsyncParallelHook [#](#t94.1.1 AsyncParallelHook)
tap
let {AsyncParallelHook}=require('tapable');
class AsyncParallelHook1{
constructor() {
this.tasks=[];
}
tap(name,task) {
this.tasks.push(task);
}
callAsync() {
this.tasks.forEach(task => task(...arguments));
Array.from(arguments).pop()();
}
}
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapAsync
//let {AsyncParallelHook}=require('tapable');
class AsyncParallelHook{
constructor() {
this.tasks=[];
}
tapAsync(name,task) {
this.tasks.push(task);
}
callAsync() {
let args=Array.from(arguments);
let callback=args.pop();
let i=0,size = this.tasks.length;
function done() {
if (++i == size) {
callback(null);
}
}
this.tasks.forEach(task => {
task(...args,done);
});
}
}
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
callback();
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(3);
callback();
},3000)
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapPromise
//let {AsyncParallelHook}=require('tapable');
class AsyncParallelHook{
constructor() {
this.tasks=[];
}
tapPromise(name,task) {
this.tasks.push(task);
}
promise() {
let args=Array.from(arguments);
let callback=args.pop();
let promises = this.tasks.map(task => task());
return Promise.all(promises);
}
}
let queue = new AsyncParallelHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(1);
resolve();
},1000)
});
});
queue.tapPromise('2',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zxmf').then(()=>{
console.timeEnd('cost');
})
4.1.2 AsyncParallelBailHook [#](#t104.1.2 AsyncParallelBailHook)
let {AsyncParallelBailHook} = require('tapable');
let queue = new AsyncParallelBailHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
4.2 AsyncSeries [#](#t114.2 AsyncSeries)
4.2.1 AsyncSeriesHook [#](#t124.2.1 AsyncSeriesHook)
tap
let {AsyncSeriesHook} = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapAsync
//let {AsyncParallelBailHook}=require('tapable');
class AsyncParallelBailHook{
constructor() {
this.tasks=[];
}
tap(name,task) {
this.tasks.push(task);
}
callAsync() {
let args=Array.from(arguments);
let callback=args.pop();
let i=0,size = this.tasks.length;
function done() {
if (++i == size) {
callback(null);
}
}
for (let i=0;i<this.tasks.length;i++){
let ret=this.tasks[i](...args,done);
if (ret) break;
}
}
}
let queue = new AsyncParallelBailHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapPromise
let {AsyncSeriesHook} = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve){
setTimeout(function(){
console.log(1);
resolve();
},1000)
});
});
queue.tapPromise('2',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zxmf').then(err=>{
console.log(err);
console.timeEnd('cost');
});
4.2.2 AsyncSeriesBailHook [#](#t134.2.2 AsyncSeriesBailHook)
tap
let {AsyncSeriesBailHook} = require('tapable');
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tap('1',function(name){
console.log(1);
return "Wrong";
});
queue.tap('2',function(name){
console.log(2);
});
queue.tap('3',function(name){
console.log(3);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tabAsync
//let {AsyncSeriesBailHook}=require('tapable');
class AsyncSeriesBailHook{
constructor() {
this.tasks=[];
}
tapAsync(name,task) {
this.tasks.push(task);
}
callAsync() {
let args=Array.from(arguments);
let callback=args.pop();
let i=0,size = this.tasks.length;
let next=(err) => {
if (err) return callback(err);
let task=this.tasks[i++];
task?task(...args,next):callback();
}
next();
}
}
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
callback('wrong');
},1000)
});
queue.tapAsync('2',function(name,callback){
setTimeout(function(){
console.log(2);
callback();
},2000)
});
queue.tapAsync('3',function(name,callback){
setTimeout(function(){
console.log(3);
callback();
},3000)
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapPromise
let {AsyncSeriesBailHook} = require('tapable');
let queue = new AsyncSeriesBailHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(1);
//resolve();
reject();
},1000)
});
});
queue.tapPromise('2',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zxmf').then(err=>{
console.log(err);
console.timeEnd('cost');
},err=>{
console.log(err);
console.timeEnd('cost');
});
4.2.3 AsyncSeriesWaterfallHook [#](#t144.2.3 AsyncSeriesWaterfallHook)
tap
let {AsyncSeriesWaterfallHook} = require('tapable');
let queue = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
queue.tap('1',function(name,callback){
console.log(1);
});
queue.tap('2',function(data){
console.log(2,data);
});
queue.tap('3',function(data){
console.log(3,data);
});
queue.callAsync('zxmf',err=>{
console.log(err);
console.timeEnd('cost');
});
tapAsync
//let {AsyncSeriesBailHook}=require('tapable');
class AsyncSeriesWaterfallHook{
constructor() {
this.tasks=[];
}
tapAsync(name,task) {
this.tasks.push(task);
}
callAsync() {
let args=Array.from(arguments);
let callback=args.pop();
let i=0,size = this.tasks.length;
let next=(err,data) => {
if (err) return callback(err);
let task=this.tasks[i++];
if (task) {
if (i==0) {
task(...args,next);
} else {
task(data,next);
}
} else {
callback(err,data);
}
}
next();
}
}
let queue = new AsyncSeriesWaterfallHook(['name']);
console.time('cost');
queue.tapAsync('1',function(name,callback){
setTimeout(function(){
console.log(1);
callback(null,1);
},1000)
});
queue.tapAsync('2',function(data,callback){
setTimeout(function(){
console.log(2);
callback(null,2);
},2000)
});
queue.tapAsync('3',function(data,callback){
setTimeout(function(){
console.log(3);
callback(null,3);
},3000)
});
queue.callAsync('zxmf',(err,data)=>{
console.log(err,data);
console.timeEnd('cost');
});
tapPromise
let {AsyncSeriesHook} = require('tapable');
let queue = new AsyncSeriesHook(['name']);
console.time('cost');
queue.tapPromise('1',function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(1);
//resolve();
reject();
},1000)
});
});
queue.tapPromise('2',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(2);
resolve();
},2000)
});
});
queue.tapPromise('3',function(name,callback){
return new Promise(function(resolve){
setTimeout(function(){
console.log(3);
resolve();
},3000)
});
});
queue.promise('zxmf').then(err=>{
console.log(err);
console.timeEnd('cost');
},err=>{
console.log(err);
console.timeEnd('cost');
});
#
4.tapableconst {Tapable,SyncHook} = require("tapable");
const t = new Tapable();
t.hooks = {
myHook: new SyncHook()
};
let called = 0;
t.plugin("my-hook", () => called++);
t.hooks.myHook.call();
t.plugin("my-hook", () => called += 10);
t.hooks.myHook.call();
console.log(called);
Gitalking ...
Be the first guy leaving a comment!