banner
banner
banner
NEWS LETTER

webpack --- 第三篇Tapable

Scroll down

了解webpack Plugin之前应该掌握Tapable
在 Webpack 的编译过程中,本质上通过 Tapable 实现了在编译过程中的一种发布订阅者模式的插件 Plugin 机制。

  • Tapable提供了一系列事件的发布订阅者API,通过Tapable使用者可以注册事件,从而在不同实际去触发注册的事件进行执行

官方提供的九种钩子

  • SyncHook
  • SyncBailHook
  • SyncWaterfallHook
  • SyncLoopHook
  • AsyncParallelHook
  • AsyncParallelBaiHook
  • AsyncSeriesHook
  • AsyncSeriesBailHook
  • AsyncSeriesWaterfallHook

Tapable中所有注册的事件可以分为同步、异步两种执行方式

  • 同步: 表示注册的事件函数会同步进行执行(Sync前缀)
  • 异步: 表示注册的事件函数会异步进行执行(Async前缀)
  • 异步串行钩子(AsyncSeries):可以被串联(连续按照顺序调用)执行的异步钩子函数
  • 异步并行钩子(AsyncParalle):可以被并联(并发调用)执行的异步钩子函数
  • 同步钩子唯一的注册事件的方法是tap,通过call方法调用执行
  • 异步钩子可以通过tap、tapAsync、tapPromise三种方式来注册,通过对应的call、callAsync、promise三种方式来触发注册的函数

Tapable 按照执行机制分类

  • Basic Hook:基本类型钩子,仅执行钩子注册的事件,不关心被调用事件的返回值
  • Waterfall:瀑布类型的钩子,会在注册事件执行时将事件函数执行非undefined的返回值传递给接下来的事件函数作为参数,其他的与基本类型钩子类似
  • Bail:保险类型钩子,在基础类型钩子上增加一个保险机制,如果任意一个注册函数执行返回非undefined>的值,那么整个钩子执行过程会立即中断,之后的注册事件就不会调用
  • Loop: 循环类型钩子,通过 call 调用时,如果任意一个注册的事件函数返回值非 undefeind,那么会立即重头开始重新执行所有的注册事件函数,直到所有被注册的事件函数都返回 undefined
  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const {SyncHook, SyncBailHook, SyncWaterfallHook,SyncWaterfallHook } = require('tapable')
    const hook = new SyncHook(['arg1','arg2','arg3']) // 这个就换钩子名,其他一样
    # SyncHook
    // 初始化同步钩子
    重点:数组中对应的字符串个数
    // 注册事件
    ▫️▪ 通过tap函数监听对应的事件,注册事件时接受两个参数:
    ▫️▪ ️第一个参数是 `字符串 | 对象``仅作标识`
    ▫️▪ 第二个参数表示`本次注册的函数`,在调用时会执行这个函数
    hook.tap('flag1',(arg1,arg2,arg3) => {})
    // 调用事件并传递执行参数
    ▫️▪ 通过call方法传入对应的参数,调用注册在hook内部的事件函数执行,同时将call方法`传入的参数传递``每一个`注册的`事件`函数作为`实参`进行调用
    hook.call('1','2','3')
    # SyncBailHook
    // 注册事件
    hook.tap('flag1',(arg1,arg2,arg3) =>{
    // 存在返回值,阻断后面注册事件的调用
    return true
    })
    //调用事件
    hook.call('1','2','3')
  • 参考
    Tapable讲解

拦截器

  • Tapable 提供的所有 Hook 都支持注入 Interception ,可以通过拦截器对整个Tapable发布/订阅流程进行监听
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    hook.intercept({
    // 每次通过 tap、tapAsync、tapPromise 方法注册事件函数时,会触发 register 拦截器。
    // 并且接受 tap 作为参数, 还可以对注册事件进行修改;
    register: (tapInfo) => {
    console.log(`${tapInfo.name} is doing its job`);
    return tapInfo
    },
    // 通过hook实例对象上的call方法时候触发拦截器,接受的参数为调用 Hook 时传入的参数。
    call: (arg1, arg2, arg3) => {},
    // 在调用被注册的每一个事件函数之前执行,接受参数为对应的 Tap 对象。
    tap: (tap) => {},
    // loop类型钩子中 每次重新开始 loop 之前会执行该拦截器,拦截器函数接受的参数为调用时传入的参数。
    loop: (...args) => {},
    });

API

Before && stage

  • before 属性的值为数组 | 字符串,值为注册事件对象时的名称,它可以让当前事件在对应标识事件执行。
  • stage 属性的值为数字,数字越大事件回调执行的越晚,支持传入负数,不传默认为0
  • 使用:在注册事件函数,第一个参数为对象时,在这个对象添加stage和before来控制本次注册事件的执行时机
  • 如果同时使用 before 和 stage 时,会优先处理 before ,在满足 before 的条件之后才会进行 stage 的判断。不建议同时使用
    1
    2
    3
    4
    5
    6
    7
    8
    hook.tap({
    name: 'flag1'
    },()=>{})
    hook.tap({
    name:'flag2',
    // flag2 会在flag1前执行
    before:'flag1'
    },()=> {})

HookMap

  • 辅助类,管理Hook
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 创建HookMap实例
    const keyedHook = new HookMap((key) => new SyncHook(['arg']));
    // 在keyedHook中创建一个name为key1的hook,同时为该hook通过tap注册事件
    keyedHook.for('key1').tap('Plugin 1', (arg) => {
    console.log('Plugin 1', arg);
    });
    // 从HookMap中拿到name为key1的hook
    const hook = keyedHook.get('key1');
    if (hook) {
    // 通过call方法触发Hook
    hook.call('hello');
    }
  • MultiHook – 不常见
  • Context – 即将废弃
其他文章
cover
webpack --- 第四篇
  • 24/11/01
  • 16:52
  • 前端工程化工具
cover
webpack --- 第二篇
  • 24/11/01
  • 16:52
  • 前端工程化工具
目录导航 置顶
  1. 1. 官方提供的九种钩子
  2. 2. Tapable中所有注册的事件可以分为同步、异步两种执行方式
  3. 3. Tapable 按照执行机制分类
  4. 4. 拦截器
  5. 5. API
请输入关键词进行搜索