说明
玩转 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 类型
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
,结果如下