基于数据结构从源码解析webpack核心模块tapable

mac2024-03-25  25

webpack作为前端打包的重要工具之一,我们有必要深入掌握webpack的底层数据结构。官方文档上直接给出了webpack的核心模块tapable,但是并没有给出特别详细的介绍其实现原理和内部实现,本文从源码触发,来解析下tapable的数据结构和方法属性,这对于掌握webpack打包机制的理解是很有帮助的。

总览:

hook.js数据结构:

constructor(args) { if (!Array.isArray(args)) args = []; this._args = args; this.taps = []; this.interceptors = []; this.call = this._call; this.promise = this._promise; this.callAsync = this._callAsync; this._x = undefined; }

两个集合,taps集合,interceptors集合,并定义了三个操作tap的方法tap, tapAsync, tapPromise,对应的还有三个创建委托函数(将监听函数转化为字符串)的方法_call, _promise, _callAsync

HookCodeFactory

各种钩子的工厂类基础类,每个钩子的工厂类会继承HookCodeFactory。比如syncHook

const Hook = require("./Hook"); const HookCodeFactory = require("./HookCodeFactory"); class SyncHookCodeFactory extends HookCodeFactory { content({ onError, onDone, rethrowIfPossible }) { return this.callTapsSeries({ onError: (i, err) => onError(err), onDone, rethrowIfPossible }); } } const factory = new SyncHookCodeFactory(); class SyncHook extends Hook { tapAsync() { throw new Error("tapAsync is not supported on a SyncHook"); } tapPromise() { throw new Error("tapPromise is not supported on a SyncHook"); } compile(options) { factory.setup(this, options); return factory.create(options); } } module.exports = SyncHook;

说明:各种钩子继承Hook类之后,会定义compile方法,该方法调用了工厂类实例,最终和HookCodeFactory联系起来,在各种钩子上去执行HookCodeFactory的方法

HookCodeFactory的方法:

主要实现了串行,并行,循环,执行单个监听函数的方法,也就是taps出栈的方法

HookMap的数据结构

constructor(factory) { this._map = new Map(); this._factory = factory; this._interceptors = []; }

可以看出,在hookMap内定义了字典的数据结构来存储hook实例

for(key) { const hook = this.get(key); if (hook !== undefined) { return hook; } let newHook = this._factory(key); const interceptors = this._interceptors; for (let i = 0; i < interceptors.length; i++) { newHook = interceptors[i].factory(key, newHook); } this._map.set(key, newHook); return newHook; }

for方法将传入的factory的hook设置到字典

MultiHook

constructor(hooks) { this.hooks = hooks; } tap(options, fn) { for (const hook of this.hooks) { hook.tap(options, fn); } } tapAsync(options, fn) { for (const hook of this.hooks) { hook.tapAsync(options, fn); } } tapPromise(options, fn) { for (const hook of this.hooks) { hook.tapPromise(options, fn); } }

批量操作hooks

其余钩子

其余的钩子函数都具有类似性,根据串行,并行或者其他在钩子工厂实例的content方法中执行不同的HookCodeFactory方法

比如:

 

总结:

同步钩子:

SyncBailHook:类似于 SyncHook,执行过程中注册的回调返回非 undefined 时就停止不在执行。SyncWaterfallHook:接受至少一个参数,上一个注册的回调返回值会作为下一个注册的回调的参数。SyncLoopHook:有点类似 SyncBailHook,但是是在执行过程中回调返回非 undefined 时继续再次执行当前的回调。

异步钩子与之相同,这里不再阐述具体实现原理。

图解钩子类型:

参考:https://segmentfault.com/a/1190000020146256

           https://www.cnblogs.com/Darlietoothpaste/p/10474871.html

最新回复(0)