webpack原理篇(五十三):Tapable插件架构与Hooks设计
Posted 凯小默
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack原理篇(五十三):Tapable插件架构与Hooks设计相关的知识,希望对你有一定的参考价值。
说明
玩转 webpack 学习笔记
compiler
上一节里面有个重要的东西就是 compiler
下面找一下这个东东,在 my-project\\node_modules\\webpack\\lib\\webpack.js
里面可以看到
这里的 Compiler 跟 MultiCompiler 分别引用了不同的 js
const Compiler = require("./Compiler");
const MultiCompiler = require("./MultiCompiler");
找到 my-project\\node_modules\\webpack\\lib\\Compiler.js
可以看到 Compiler 继承了 Tapable
Webpack 的本质
Webpack 可以将其理解是一种基于事件流的编程范例,一系列的插件运行。
核心对象 Compiler 继承 Tapable:
class Compiler extends Tapable
// ...
核心对象 Compilation 继承 Tapable
class Compilation extends Tapable
// ...
Tapable 是什么?
Tapable 是一个类似于 Node.js 的 EventEmitter 的库, 主要是控制钩子函数的发布与订阅,控制着 webpack 的插件系统。
Tapable 库暴露了很多 Hook(钩子)类,为插件提供挂载的钩子
const
SyncHook, // 同步钩子
SyncBailHook, // 同步熔断钩子(遇到 return 直接返回)
SyncWaterfallHook, // 同步流水钩子(结果可以传递给下一个插件)
SyncLoopHook, // 同步循环钩子
AsyncParallelHook, // 异步并发钩子
AsyncParallelBailHook, // 异步并发熔断钩子
AsyncSeriesHook, // 异步串行钩子
AsyncSeriesBailHook, // 异步串行熔断钩子
AsyncSeriesWaterfallHook // 异步串行流水钩子
= require("tapable");
Tapable hooks 类型
type | function |
---|---|
Hook | 所有钩子的后缀 |
Waterfall | 同步方法,但是它会传值给下一个函数 |
Bail | 熔断:当函数有任何返回值,就会在当前执行函数停止 |
Loop | 监听函数返回true表示继续循环,返回undefine表示结束循环 |
Sync | 同步方法 |
AsyncSeries | 异步串行钩子 |
AsyncParallel | 异步并行执行钩子 |
Tapable 的使用:new Hook 新建钩子
Tapable 暴露出来的都是类方法,new 一个类方法获得我们需要的钩子
class 接受数组参数 options ,非必传。类方法会根据传参,接受同样数量的参数。
const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);
Tapable 的使用:钩子的绑定与执行
Tabpack 提供了同步 &
异步绑定钩子的方法,并且他们都有绑定事件和执行事件对应的方法。
Async* | Sync* |
---|---|
绑定: tapAsync/tapPromise/tap | 绑定: tap |
执行: callAsync/promise | 执行: call |
Tapable 的使用:hook 基本用法示例
const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);
// 绑定事件到webapck事件流
hook1.tap('hook1', (arg1, arg2, arg3) => console.log(arg1, arg2, arg3)) //1,2,3
// 执行绑定的事件
hook1.call(1,2,3)
Tapable 的使用:实际例子演示
新建项目
1、我们先新建一个项目 tapable-kaimo
,然后执行下面命令
npm init -y
npm i tapable
先添加一个 index.js 文件,输入下面代码
const
SyncHook
= require('tapable');
const hook = new SyncHook(["arg1", "arg2", "arg3"]);
hook.tap("hook1", (arg1, arg2, arg3) =>
console.log(arg1, arg2, arg3);
);
hook.call(1, 2, 3);
运行 node index.js
结果如下
实现下面例子
定义一个 Car 方法,在内部 hooks 上新建钩子。分别是同步钩子 accelerate、brake( accelerate 接受一个参数)、异步钩子 calculateRoutes。
使用钩子对应的绑定和执行方法
calculateRoutes 使用 tapPromise 可以返回一个 promise 对象
新建一个 car.js 文件,添加下面代码
const
SyncHook,
AsyncSeriesHook
= require('tapable');
// 创建 Car 类
class Car
constructor()
this.hooks =
accelerate: new SyncHook(['newSpeed']), // 加速 hook
brake: new SyncHook(), // 刹车 hook
calculateRoutes: new AsyncSeriesHook(['source', 'target', 'routesList']) // 计算路径 hook
// 实例化 Car
const kaimoCar = new Car();
// 绑定同步钩子
kaimoCar.hooks.brake.tap('WarningLampPlugin', () =>
console.log('WarningLampPlugin');
)
// 绑定同步钩子 并传参
kaimoCar.hooks.accelerate.tap('LoggerPlugin', newSpeed =>
console.log(`Accelerate to $newSpeed`);
)
// 绑定一个异步 Promise 钩子
kaimoCar.hooks.calculateRoutes.tapPromise('calculateRoutes tapPromise', (source, target, routesList, callback) =>
return new Promise((resolve, reject) =>
setTimeout(() =>
console.log(`tapPromise to $source $target $routesList`);
resolve()
, 1000)
)
)
/*****************下面开始执行***************/
kaimoCar.hooks.brake.call();
kaimoCar.hooks.accelerate.call(313);
console.time('kaimoCar cost');
kaimoCar.hooks.calculateRoutes.promise('Async', 'hook', 'kaimo demo').then(() =>
console.timeEnd('kaimoCar cost');
, err =>
console.error(err);
console.timeEnd('kaimoCar cost');
)
运行命令执行 node car.js
,结果如下
以上是关于webpack原理篇(五十三):Tapable插件架构与Hooks设计的主要内容,如果未能解决你的问题,请参考以下文章