webpack源码分析——enhanced-resolve库之getType、normalize、join和cachedJoin函数

news/2024/10/24 10:27:36/

一、PathType 路径类型

const PathType = Object.freeze({Empty: 0, // 空Normal: 1, // 默认值Relative: 2, // 相对路径AbsoluteWin: 3, // win 下的绝对路径AbsolutePosix: 4, // posix 下的绝对路径Internal: 5 // enhanced-resolve 内部自定义的一种类型,具体是用来 escaping,具体说明:https://www.npmjs.com/package/enhanced-resolve
});

注:什么是Posix?点击查看path

函数中用到的变量定义

const path = require("path");const CHAR_HASH = "#".charCodeAt(0);
const CHAR_SLASH = "/".charCodeAt(0);
const CHAR_BACKSLASH = "\\".charCodeAt(0);
const CHAR_A = "A".charCodeAt(0);
const CHAR_Z = "Z".charCodeAt(0);
const CHAR_LOWER_A = "a".charCodeAt(0);
const CHAR_LOWER_Z = "z".charCodeAt(0);
const CHAR_DOT = ".".charCodeAt(0);
const CHAR_COLON = ":".charCodeAt(0);const posixNormalize = path.posix.normalize; 
const winNormalize = path.win32.normalize;

二、getType 函数

该函数通过传入的路径,判断并返回其类型值。返回的类型值为PathType中定义的值之一

  1. 根据传入的路径length判断
switch (p.length) {case 0:return PathType.Empty; // 当length ==0 时, 返回 PathType.Emptycase 1: {const c0 = p.charCodeAt(0);switch (c0) {case CHAR_DOT:return PathType.Relative; // 如果开头的第一个字符为‘.’时,返回PathType.Relativecase CHAR_SLASH:return PathType.AbsolutePosix; // 如果开头的第一个字符为‘/’时,返回PathType.AbsolutePosixcase CHAR_HASH:return PathType.Internal; // 如果开头的第一个字符为‘#’时,返回PathType.Internal}return PathType.Normal; // 没有匹配到返回兜底值PathType.Normal}case 2: {const c0 = p.charCodeAt(0);switch (c0) {case CHAR_DOT: { // 当第一个字符为‘.’const c1 = p.charCodeAt(1);switch (c1) {case CHAR_DOT:case CHAR_SLASH:return PathType.Relative; // 当第二个字符为‘.’或‘/’时。返回PathType.Relative}return PathType.Normal; // 没有匹配到返回兜底值PathType.Normal}case CHAR_SLASH:return PathType.AbsolutePosix; // 当第二个字符为‘/’时。返回PathType.AbsolutePosixcase CHAR_HASH:return PathType.Internal; // 当第二个字符为‘#’时。返回PathType.Internal}const c1 = p.charCodeAt(1);if (c1 === CHAR_COLON) {  // 判断是否时win平台if ((c0 >= CHAR_A && c0 <= CHAR_Z) ||(c0 >= CHAR_LOWER_A && c0 <= CHAR_LOWER_Z)) {return PathType.AbsoluteWin; // 是 win 返回PathType.AbsoluteWin}}return PathType.Normal; // 没有匹配到返回兜底值PathType.Normal}}
  1. 当路径length大于2时
	const c0 = p.charCodeAt(0); // 获取第一个字符switch (c0) {case CHAR_DOT: {const c1 = p.charCodeAt(1);switch (c1) {case CHAR_SLASH:return PathType.Relative; // 当第一个字符为‘.’第二个字符为‘/’时,返回PathType.Relativecase CHAR_DOT: {const c2 = p.charCodeAt(2);if (c2 === CHAR_SLASH) return PathType.Relative; // 当第一个字符为‘.’第二个字符为‘.’和第三个字符为‘/’时,返回PathType.Relativereturn PathType.Normal; // 没有匹配到返回兜底值PathType.Normal}}return PathType.Normal;// 没有匹配到返回兜底值PathType.Normal}case CHAR_SLASH:return PathType.AbsolutePosix; // 当第一个字符为‘/’时,返回PathType.AbsolutePosixcase CHAR_HASH:return PathType.Internal;// 当第一个字符为‘#’时,返回PathType.Internal}const c1 = p.charCodeAt(1);if (c1 === CHAR_COLON) { // 判断是否在win下,并且为绝对路径const c2 = p.charCodeAt(2);if ((c2 === CHAR_BACKSLASH || c2 === CHAR_SLASH) &&((c0 >= CHAR_A && c0 <= CHAR_Z) ||(c0 >= CHAR_LOWER_A && c0 <= CHAR_LOWER_Z))) {return PathType.AbsoluteWin;}}return PathType.Normal;// 没有匹配到返回兜底值PathType.Normal

例1:win上的绝对路径
请添加图片描述
例2:posix上的绝对路径
请添加图片描述

三、normalize函数

该函数通过调用node的path.normalize方法规范化给定的 path

  1. 对传入的路径调用getType函数根据返回值,对Empty、AbsoluteWin和Relative三种类型进行处理
    switch (getType(p)) {case PathType.Empty:case PathType.AbsoluteWin:case PathType.Relative: 
    }
    
  2. 当为路径类型为PathType.Empty
    return p; // 直接返回
    
  3. 当为路径类型为PathType.AbsoluteWin
    return winNormalize(p); // path.win32.normalize
    
  4. 当为路径类型为PathType.Relative
    const r = posixNormalize(p); // path.posix.normalize
    return getType(r) === PathType.Relative ? r : `./${r}`; // 因为 ‘./webpack’ 这样的路径被 posixNormalize 函数处理后 变为 ‘webpack’,所有需要这一行进行特殊处理
    

源码

const normalize = p => {switch (getType(p)) {case PathType.Empty:return p;case PathType.AbsoluteWin:return winNormalize(p);case PathType.Relative: {const r = posixNormalize(p);return getType(r) === PathType.Relative ? r : `./${r}`;}}return posixNormalize(p);
};

四、join函数

该函数进行路径进行拼接

  1. 如果 request 变量没有传入
    if (!request) return normalize(rootPath); // 直接调用normalize 函数返回
    
  2. 根据rootPath和request类型判断
    const requestType = getType(request); // 首先判断 requestType 类型
    switch (requestType) { // 如果时绝对路径,就不需要拼接了,直接调用 posixNormalize/winNormalize  返回case PathType.AbsolutePosix:return posixNormalize(request);case PathType.AbsoluteWin:return winNormalize(request);
    }
    switch (getType(rootPath)) { // 判断 rootPath 类型,上面 request 类型已经排除了绝对路径的情况,所有判断 rootPath 类型后直接和request进行拼接case PathType.Normal:case PathType.Relative:case PathType.AbsolutePosix:return posixNormalize(`${rootPath}/${request}`);case PathType.AbsoluteWin:return winNormalize(`${rootPath}\\${request}`);
    }
    /*** request 类型不为 AbsolutePosix和AbsoluteWin* rootPath 类型不为 Normal、Relative、AbsolutePosix和AbsoluteWin时* 进入下面阶段*/
    switch (requestType) {case PathType.Empty: // request 为空时(这里不存在因为在函数顶部已经错了空的判断),直接返回 rootPath。但是 rootPath 也有可能为空return rootPath;case PathType.Relative: {const r = posixNormalize(rootPath);return getType(r) === PathType.Relative ? r : `./${r}`;}
    }
    
  3. 兜底
    return posixNormalize(rootPath);
    

源码

const join = (rootPath, request) => {if (!request) return normalize(rootPath);const requestType = getType(request);switch (requestType) {case PathType.AbsolutePosix:return posixNormalize(request);case PathType.AbsoluteWin:return winNormalize(request);}switch (getType(rootPath)) {case PathType.Normal:case PathType.Relative:case PathType.AbsolutePosix:return posixNormalize(`${rootPath}/${request}`);case PathType.AbsoluteWin:return winNormalize(`${rootPath}\\${request}`);}switch (requestType) {case PathType.Empty:return rootPath;case PathType.Relative: {const r = posixNormalize(rootPath);return getType(r) === PathType.Relative ? r : `./${r}`;}}return posixNormalize(rootPath);
};

五、cachedJoin函数

该函数在 join 函数的基础上加上缓存

  1. 判断 rootPath 是否在缓存中
    const joinCache = new Map();let cache = joinCache.get(rootPath); // 从 map 中获取 rootPath
    if (cache === undefined) { // rootPath 没有在缓存中joinCache.set(rootPath, (cache = new Map())); // 新增缓存
    } else {cacheEntry = cache.get(request); // 在缓存中,根据request获取rootPath对应缓存的值if (cacheEntry !== undefined) return cacheEntry;
    }
    cacheEntry = join(rootPath, request);
    cache.set(request, cacheEntry); // 没有在缓存中时,对当前路径进行缓存
    return cacheEntry;
    

http://www.ppmy.cn/news/1426181.html

相关文章

【redis】hash和list常用命令

hash类型 Redis自身已经是键值对结构了。Redis自身的键值对就是通过哈希的方式来组织的。 把key这一层组织完成之后,到了value这一层。value的其中一种类型还可以再是哈希。哈希类型中的映射关系通常称为field-value,用于区分Redis整体的键值对(key-value)。注意这里的 value…

循环双链表的操作

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 每一个裂缝都是为透出光而努力&#…

【深度学习实战(12)】训练之模型参数初始化

在深度学习模型的训练中&#xff0c;权重的初始值极为重要。一个好的初始值&#xff0c;会使模型收敛速度提高&#xff0c;使模型准确率更精确。一般情况下&#xff0c;我们不使用全0初始值训练网络。为了利于训练和减少收敛时间&#xff0c;我们需要对模型进行合理的初始化。 …

记录一个hive中因没启yarn导致的spark引擎跑insert语句的报错

【背景说明】 刚在hive中配置了Spark引擎&#xff0c;在进行Hive on Spark测试时报错&#xff0c; 报错截图如下&#xff1a; [atguiguhadoop102 conf]$ hive which: no hbase in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/mod…

前端开发与html学习笔记

一、前端开发概述 前端开发&#xff1a;也叫做web前端开发&#xff0c;它指的是基于web的互联网产品的页面(也可叫界面)开发及功能开发互联网产品&#xff1a;指网站为满足用户需求而创建的用于运营的功能及服务&#xff0c;百度搜索、淘宝、QQ、微博、网易邮箱等都是互联网产…

如何搭建线下陪玩系统(本地伴游、多玩圈子)APP小程序H5多端前后端源码交付,支持二开!

一、卡顿的优化方法 1、对陪玩系统源码中流媒体传输的上行进行优化&#xff0c;通过提升推流端的设备性能配置、推流边缘CDN节点就近选择等方式解决音视频数据源流的卡顿。 2、对陪玩系统源码中音视频数据的下载链路进行优化&#xff0c;通过选择更近更优质的CDN边缘节点来减少…

WordPress 多站点切换域名完整指南:详细步骤和注意事项

因为公司的需要&#xff0c;需要对 WordPress 多站点进行域名切换, 一开始我也找了相关的方案和教程&#xff0c;但是很可惜&#xff0c;国内这一块网上的资料几乎为0&#xff0c;所以我把实现的过程写了一篇文章分享出来&#xff0c;为后来的人铺路。 开始之前&#xff0c;先…

【项目实战】记录一次PG数据库迁移至GaussDB测试(下)

上一篇分享了安装、迁移&#xff0c;本篇将继续分享迁移前操作、 DRS迁移数据、迁移后一致性检查、问题总结及解决方法。 目录 四、迁移前操作 4.1 源端(PG) 4.2 目标端(GaussDB库) 五、DRS迁移数据 5.1 创建复制用户 5.2创建迁移任务。 六、迁移后一致性检查 6.1使用…