说明
玩转 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* |
绑定: | 绑定: tap |
执行: | 执行: call |
Tapable 的使用:hook 基本用法示例
const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);
// 绑定事件到webapck事件流
hook1.tap('hook1', (arg1, arg2,) => console.log(arg1, arg2, arg3)) //1,2,3
// 执行绑定的事件
hook1.call(1,2,3)
Tapable 的使用:实际例子演示
新建项目
1、我们先新建一个项目 tapable-kaimo
,然后执行下面命令
npm init -y
npm
先添加一个 index.js 文件,输入下面代码
const {
SyncHook
} = require('tapable');
const hook = new SyncHook(["arg1", "arg2", "arg3"]);
hook.tap("hook1", (arg1, arg2,) => {
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,) => {
return new Promise((resolve,) => {
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
,结果如下