Fork me on GitHub

webpack之Tapable

webpack 里面使用的

Tapable

webpack 是一种事件流机制,将各个插件串联起来,wbpack 使用 Tapable 进行编译

  • 安装
1
yarn add apable
  • 同步钩子 SyncHook

    • 使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    let { SyncHook } = require('tapable');
    class Lesson{
    constructor(){
    this.hooks={
    arch: new SyncHook(['name])
    }
    }
    tap(){//注册监听函数
    this.hooks.arch.tap('node',function(){
    console.log('node',name)
    })
    this.hooks.arc.tap('node',function(){
    console.log('node',name)
    })
    }
    start(){
    this.hooks.arch.call('fdd')
    }

    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    • SyncHook 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class SyncHook{
    constructor(args){ // args =》['name']
    this.tasks=[]
    }
    tap(name, task){
    this.task.push(task)
    },
    call(...args){
    this.tasks.forEach(task=> task(...args))
    }
    }
    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('fdd')
  • SyncBailHook 可熔断钩子 return 非 undefined 的值就停止向下执行

    • 使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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 '停止学习'
    })
    this.hooks.arch.tap('React',function(name){
    console.log('React',name)
    })

    }
    start(){
    this.hooks.arch.call('fdd')
    }
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    • SyncBailHook 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class SyncBailHook{
    constructor(arg){
    this.tasks=[]
    }
    tap(name,task){
    this.tasks.push(task)
    }
    call(...args){
    let ret; //当前task的返回值
    let index=0;//当前要执行的第一个
    do{
    ret = this.tasks[ index++ ](...args)
    }while(ret===undefined && index<this.tasks.length)
    }
    }
    let hook= new SyncBailHook(['name'])
    hook.tap('React',function(name){
    console.log('React',name)
    })
    hook.tap('node',function(name){
    console.log('node',name)
    })
    hook.call('fdd')
  • SyncWaterfallHook 瀑布流钩子

    • 使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    let { SyncWaterfallHook } = require('tapable');
    class Less{
    constructor(){
    this.hooks={
    arch: new SyncWaterfallHook(['name'])
    }
    }
    tap(name, task){
    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('fdd')
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    }
    • SyncWaterfallHook 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class  SyncWaterfallHook{
    constructor(args){
    this.tasks=[]...args
    }
    tap(name, task){
    this.tasks.push(task)
    }
    call(...args){
    let [ first, ...others] = this.tasks;
    let ret = first(...args)
    others.reduce((a, b) => b(a),ret) /将a的结果传递给b,初始值为第一个函数的执行结果
    }
    }
    let hook= new SyncWaterfallHook(['name']);
    hook.tap('React', function(name){
    console.log('React', name);
    return 'ReactOk'
    })
    hook.tap('node', function(data){
    console.log('node', data)
    })
    hook.tap('webpack', function(data){
    console.log('webpack', data)
    })
    hook.call('fdd')
  • SyncLoopHook 同步遇到某个不返回 undefinedj 的监听函数循环执行

    • 使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    let { SyncLoopHook } = require('tapable');
    class Less{
    constructor(){
    this.index=0;
    this.hooks={
    arch: new SyncLoopHook(['name'])
    }
    }
    tap(name, task){
    this.hooks.arch.tap('node',(name) =>{
    console.log('node', name);
    return index++===3?return undefined: 'node学习'
    })
    this.hooks.arch.tap('React',(data) =>{
    console.log('React',data)
    })
    }
    call(){
    this.hooks.arch.call('fdd')
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    }
    • SyncLoopHook 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class  SyncLoopHook{
    constructor(args){
    this.tasks=[]...args
    }
    tap(name, task){
    this.tasks.push(task)
    }
    call(...args){
    this.tasks.forEach(task => {
    let ret;
    do{
    ret = task(...args)
    } while(ret!== undefined)
    })
    }
    }
    let hook= new SyncLoopHook(['name']);
    let total=0
    hook.tap('React', function(name){
    console.log('React', name);
    return ++total===3?undefined:'ReactOk'
    })
    hook.tap('node', function(name){
    console.log('node', name)
    })
    hook.tap('webpack', function(name){
    console.log('webpack', name)
    })
    hook.call('fdd')
  • AsyncParallelHook 异步并行
    异步的钩子,并行执行,同发送多了请求,需要等待所有并发异步时间执行后再执行回调方法
    注册方法 tap 和 tapAsync,tapPromise

    • 使用 异步注册 tapAsync

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      let { AsyncParallelHook } = require('tapable');
      class Less{
      constructor(){
      this.hooks={
      arch: new AsyncParallelHook(['name'])
      }
      }
      tap(name, task){
      this.hooks.arch.tapAsync('node', (name, cb)=>{
      setTimeout(() => {
      console.log('node', name);
      cb()
      },1000)
      })
      this.hooks.arch.tapAsync('React',(name, cb)=>{
      setTimeout(() => {
      console.log('React', name);
      cb()
      },1000)
      })
      }
      start(){
      this.hooks.arch.callAsync('fdd',function(){
      console.log('end')
      })
      }
      let l =new Lesson()
      l.tap() //注册钩子
      l.start() //启动钩子
      }
      • AsyncParallelHook 实现原理
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      class  AsyncParallelHook{
      constructor(args){
      this.tasks=[]...args
      }
      tap(name, task){
      this.tasks.push(task)
      }
      call(...args){
      let finalCallback=args.pop() //拿到最后的回调函数
      let index = 0;
      let next = () => {
      index++;
      if(index===this.tasks.length){
      finalCallback()
      }
      }
      this.tasks.forEach(task => {
      task(...args, done)
      } )
      }
      }
      let hook= new AsyncParallelHook(['name']);
      hook.tapAsync('React', (name,cb) =>{
      setTimeout(() => {
      console.log('React', name);
      cb()
      },1000)
      })
      hook.tapAsync('node', (name,cb) => {
      setTimeout(() => {
      console.log('node', name);
      cb()
      },1000)
      })
      hook.callAsync('fdd',function(){
      console.log('end')
      })
    • 使用 promise 注册 tapPromise

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      let { AsyncParallelHook } = require('tapable');
      class Less{
      constructor(){
      this.hooks={
      arch: new AsyncParallelHook(['name'])
      }
      }
      tap(name, task){
      this.hooks.arch.tapPromise('node', (name)=>{
      return new Promise((resolve,reject) => {
      console.log('node', name);
      resolve()
      })
      })
      this.hooks.arch.tapPromise('React',(name)=>{
      return new Promise((resolve,reject) => {
      console.log('React', name);
      resolve()
      })
      })
      }
      start(){
      this.hooks.arch.promise('fdd').then(function(){
      console.log('end')
      })
      }
      let l =new Lesson()
      l.tap() //注册钩子
      l.start() //启动钩子
      }
    • AsyncParallelHook promise 注册 实现原理

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      class  AsyncParallelHook{
      constructor(args){
      this.tasks=[]...args
      }
      tapPromise(name, task){
      this.tasks.push(task)
      }
      promise(...args){
      let tasks= this.tasks.map(task =>task(...args))
      return Promise.all(tasks)
      }
      }

      let hook= new SyncWaterfallHook(['name']);
      hook.tapPromise('React', (name) =>{
      return new Promise((resolve,reject) =>
      console.log('React', name);
      resolve()
      })
      })
      hook.tapPromise('node', (name) => {
      return new Promise((resolve,reject) =>
      console.log('node', name);
      resolve()
      })
      })
      hook.promise('fdd').then(function(){
      console.log('end')
      })
  • AsyncSeriesHook 异步串行

    • 使用 异步注册 tapAsync
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    let { AsyncSeriesHook } = require('tapable');
    class Less{
    constructor(){
    this.hooks={
    arch: new AsyncSeriesHook(['name'])
    }
    }
    tap(name, task){
    this.hooks.arch.tapAsync('node', (name, cb)=>{
    setTimeout(() => {
    console.log('node', name);
    cb()
    },1000)
    })
    this.hooks.arch.tapAsync('React',(name, cb)=>{
    setTimeout(() => {
    console.log('React', name);
    cb()
    },1000)
    })
    }
    start(){
    this.hooks.arch.callAsync('fdd',function(){
    console.log('end')
    })
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    }
    • AsyncSeriesHook 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    class  AsyncSeriesHook{
    constructor(args){
    this.tasks=[]...args
    }
    tap(name, task){
    this.tasks.push(task)
    }
    call(...args){
    let finalCallback=args.pop() //拿到最后的回调函数
    let index = 0;
    let next = () => {
    if(index===this.tasks.length){
    return finalCallback()
    }
    let task = this.tasks[index++];
    task(...args, next)
    }
    next()
    }
    }
    let hook= new AsyncSeriesHook(['name']);
    hook.tapAsync('React', (name,cb) =>{
    setTimeout(() => {
    console.log('React', name);
    cb()
    },1000)
    })
    hook.tapAsync('node', (name,cb) => {
    setTimeout(() => {
    console.log('node', name);
    cb()
    },1000)
    })
    hook.callAsync('fdd',function(){
    console.log('end')
    })
    • 使用 promise 注册 tapPromise
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    let { AsyncSeriesHook } = require('tapable');
    class Less{
    constructor(){
    this.hooks={
    arch: new AsyncSeriesHook(['name'])
    }
    }
    tap(name, task){
    this.hooks.arch.tapPromise('node', (name)=>{
    return new Promise((resolve,reject)=>{
    setTimeout(() => {
    console.log('node', name);
    resolve()
    },1000)
    })
    })
    this.hooks.arch.tapPromise('React',(name)=>{
    return new Promise((resolve,reject)=>{
    setTimeout(() => {
    console.log('React', name);
    resolve()
    },1000)
    })
    })
    }
    start(){
    this.hooks.arch.promise('fdd').then(function(){
    console.log('end')
    })
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    }
    • AsyncSeriesHook promise 实现原理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    class AsyncSeriesHook{
    constructor(args){
    this.tasks=[]
    }
    tapPromise(name, task){
    this.tasks.push(task)
    }
    promise(...args){
    let [ first, ...others]=this.tasks;
    return others.reduce((p,n) => {
    return p.then(()=>n(...args))
    },first(...args))
    }
    }
    let hook= new AsyncSeriesHook(['name'])
    hook.tapPromise('React',(name) =>{
    return new Promise((resolve,reject)=>{
    setTimeout(() => {
    console.log('React', name);
    resolve()
    },1000)
    })
    })
    hook.tapPromise('node',(name) =>{
    return new Promise((resolve,reject)=>{
    setTimeout(() => {
    console.log('node', name);
    resolve()
    },1000)
    })
    })
    hook.promise('fdd').then(() => {
    console.log('end1')
    })
  • AsyncSeriesWaterfallHook 异步串行瀑布流钩子

    • 使用 tapAsync
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    let { AsyncSeriesWaterfallHook } = require('tapable');
    class Less{
    constructor(){
    this.hooks={
    arch: new AsyncSeriesWaterfallHook(['name'])
    }
    }
    tap(name, task){
    this.hooks.arch.tapAsync('node', (name, cb)=>{
    setTimeout(() => {
    console.log('node', name);
    cb(null,'result)
    },1000)
    })
    this.hooks.arch.tapAsync('React',(data, cb)=>{
    setTimeout(() => {
    console.log('React', data);
    cb(null)
    },1000)
    })
    }
    start(){
    this.hooks.arch.callAsync('fdd',function(){
    console.log('end')
    })
    }
    let l =new Lesson()
    l.tap() //注册钩子
    l.start() //启动钩子
    }
    • 实现原理 tapAsync
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    class AsyncSeriesWaterfallHook{
    constructor(args){
    this.tasks=[]
    }
    tapAsync(name, task){
    this.tasks.push(task)
    }
    callAsync(...args){
    let index =0;

    let finalCallback = args.pop();
    let next = (err, data)=>{
    let task = this.tasks[index];
    if(!task) return finalCallback();
    if(index===0){
    task(...args,next)
    }else{
    if(err === null){
    task(data,next);
    }else{
    finalCallback();
    }
    }
    index++
    }
    next()
    }
    }
    let hook= new AsyncSeriesWaterfallHook(['name'])
    hook.tapAsync('React',(name, cb) =>{
    setTimeout(() => {
    console.log('React', name);
    cb('1',111)
    },1000)
    })
    hook.tapAsync('node',(data, cb) =>{
    setTimeout(() => {
    console.log('node', data);
    cb()
    },1000)
    })
    hook.callAsync('fdd',() => {
    console.log('end1')
    })
  • 使用 promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
let { AsyncSeriesWaterfallHook } = require('tapable');
class Lesson{
constructor(){
this.hooks={
arc: new AsyncSeriesWaterfallHook(['name'])
}
}
tap(){
this.hooks.arc.tapPromise('React',(name) =>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('React', name);
resolve(111)
},1000)
})
})
this.hooks.arc.tapPromise('node',(data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('node', data);
resolve()
},1000)
})
})
}
start(){
this.hooks.arc.promise('fdd').then(()=>{
console.log('end')
})
}

}
let l = new Lesson()
l.tap()
l.start()
  • 实现原理 promise
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class AsyncSeriesWaterfallHook{
constructor(args){
this.tasks=[]
}
tapPromise(name, task){
this.tasks.push(task)
}
promise(...args){
let [ first, ...others] = this.tasks;
return others.reduce((p,n) => {
return p.then((data)=>n(data))
},first(...args))
}
}
let hook= new AsyncSeriesWaterfallHook(['name'])
hook.tapPromise('React',(name) =>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('React', name);
resolve(111)
},1000)
})

})
hook.tapPromise('node',(data) =>{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('node', data);
resolve()
},1000)
})
})
hook.promise('fdd').then(() => {
console.log('end1')
})
-------------本文结束感谢阅读-------------