涨薪面技:写个 enhanced-resolve 插件(6)

一、前文回顾

受限于篇幅,这里并没有完全完成整个流水线的注册工作,之所以不在一篇写完也是不想给各位读者带来过大的压力!

我们大致回故一下从今天的流水线内容:

  1. resolve 开始解析:注册 UnsafeCachePlugin、ParsePlugin 插件;
  2. paresed-resolve:request 解析阶段;
  3. described-resolve 描述文件已解析;
  4. raw-resolve: 原始解析阶段,处理 alias/aliasFields/extension/extensionAlias;
  5. normal-resolve: 普通解析阶段,处理 preferRealative、preferAbsolute
  6. internal: 内部解析阶段,处理 importsFields 选项声明的能力;
  7. raw-module 阶段,处理 resolve.modules、exportsFields 选项声明的能力;

二、复习 Factory.createResolver 工作流

方法来自 enhanced-resolve/lib/ResolverFactory.js 模块导出的方法 createResolver :

js 复制代码
exports.createResolver = function (options) {
 // ....
 return resolver;
};

createResolver 方法主要工作如下:总结一下,包括后面的几个阶段:

2.1 normalizeOptions 格式化选项对象

  1. normalizeOptions 格式化选项对象

2.2 创建 Resolver 实例 resolver

  1. new Resolver() 创建 resolver 实例

2.3 流水线钩子注册

调用 resolver.enuserHook 完成从 resolve 到 resolved 的流水线钩子注册

2.4 用户插件注册

和 webpack 一样,调用插件实例的 apply 方法,传入 resolver 实例。另外还处理插件为 function 类型的情况。

三、raw-module 后的流水线

3.8 // module 阶段

注册 JoinRequestPartPlugin 插件,source 钩子 module,target 钩子 resolve-as-module。处理对 @namespace/sub/pkg/file.js 这种针对带有 @ 符号的命名空间内部的子模块请求。感觉是把带有命名空间的包里面的子模块当成模块请求。起初有点好奇他为什么这么搞,这样做就一点一点的变成了一个绝度路径了,体现在插件对 path 的改写。

3.9 // resolve-as-module

  1. 判断 resolveToContext 是否为 false,如果成立(这个配置项在 webpack 官方文档没有找到,其默认值为 false),则注册 ConditionalPlugin 插件,source 钩子为resolve-as-module,target 钩子 undescribed-raw-file。条件是 { directory: false, request: "." },

  2. 注册 DirectoryExistsPlugin 插件,source 钩子:resolve-as-module,target 钩子:undescribed-resolve-in-package。path 是不是一个真实存在的目录

3.10 // undescribed-resolve-in-package

  1. 注册 DescriptionFilePlugin 插件,source 钩子 undescribed-resolve-in-package,target钩子:resolve-in-package。其实这个插件在前面注册过,其作用是读取目录下的 package.json 文件,但是此时经过前面的多个插件加工,path 已经发生了变化,此时需要重新读取 path 下面的 package.json 了。

  2. 注册 NextPlugin 插件,source 钩子:after-undescribed-resolve-in-package,target 钩子 resolve-in-package。NextPlugin 不再赘述。

3.11 // resolve-in-package

  1. 遍历 exportsFields 字段,给各个字段注册 ExportsFieldPlugin 插件,source 钩子:resolve-in-package,target 钩子:relative。exportsFields webpack.config.js.resolve.exportsFields 传送门

  2. 注册 NextPlugin,source 钩子:resolve-in-package,target 钩子:resolve-in-existing-directory

  3. 再次注册 JoinRequestPlugin 插件,source 钩子:resolve-in-existing-directory,target 钩子:relative

3.11 // resolve-in-existing-directory

注册 JoinRequestPlugin 插件,source 钩子:resolve-in-existing-directory,target:relative 钩子。

3.12 // relative

  1. 再次注册 DescriptionFilePlugin 插件,source 钩子:relative,target 钩子:described-relative
  2. 注册 NextPlugin,source 钩子:after-relative,target 钩子:described-relative

3.13 // described-relative

  1. 判断 resolveToContext 是否存在,存在注册 NextPlugin,source 钩子:described-relative,target 钩子:directory;否则,注册 ConditionalPlugin,source 钩子:described-relative,target 钩子:raw-file,条件:{ directory: false };再注册 ConditionalPlugin,source 钩子:described-relative,target 钩子:directory,条件:{ fullySpecified: false }

3.14 // directory

注册 DirectoryExistsPlugin 插件,source 钩子:directory;target 钩子:undescribed-existing-directory;校验 request.path 是否存在。

四、总结

本文接着上文的流水线注册环节讲述后续的流水线注册:

  1. module 阶段:处理 @xx 类似这种带有命名空间的内部 request,将其变成一个绝对路径;
  2. resolve-as-module:实际上就是 request 只写到文件夹,这个时候如果 resolveToContext 选项为 false 的时候则将当前 request 作为模块解析;
  3. undescribed-resolve-in-package:重新尝试读取 path 下的 package.json 文件;
  4. resolve-in-package:处理 exportsFields 字段;
  5. resolve-in-existing-directory:在已经存在的路径下解析,构造可能的 request;
  6. relative:注册 DescriptionFilePlugin 插件;
  7. described-relative:处理 resolveToContext 选项成立时,则将解析历程指向 directory 钩子;
  8. directory:注册 DirectoryExistsPlugin 插件,判断路径是否存在;
相关推荐
JUNAI_Strive_ving10 分钟前
番茄小说逆向爬取
javascript·python
看到请催我学习20 分钟前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
twins352039 分钟前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
邵泽明40 分钟前
面试知识储备-多线程
java·面试·职场和发展
qiyi.sky1 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒1 小时前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od
安冬的码畜日常1 小时前
【D3.js in Action 3 精译_027】3.4 让 D3 数据适应屏幕(下)—— D3 分段比例尺的用法
前端·javascript·信息可视化·数据可视化·d3.js·d3比例尺·分段比例尺
Q_w77422 小时前
一个真实可用的登录界面!
javascript·mysql·php·html5·网站登录
昨天;明天。今天。2 小时前
案例-任务清单
前端·javascript·css