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

一、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.mzph.cn/news/826001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序AI智能名片S2B2C商城系统:做内容、造IP、玩社群打造私域流量的新营销秘籍

在数字化浪潮汹涌的新时代&#xff0c;小程序AI智能名片S2B2C商城系统正以其独特的魅力&#xff0c;引领着营销领域的新变革。这套系统不仅将人工智能与小程序技术完美结合&#xff0c;更通过创新的S2B2C模式&#xff0c;为企业打开了一扇通往成功的大门。 面对激烈的市场竞争&…

SQL注入作业

目录 一、万能密码和二阶注入测试 1.万能密码 2.二阶注入测试 二、联合查询注入测试 1.判断注入点 2.判断当前查询语句的列数 3.查询数据库基本信息 4.查询数据库中的数据 三、报错注入 1. 报错注入函数EXTRATVALUE 2.UPDATEXML 四、盲注测试 1.布尔盲注 判断数据…

Linux搭建Discuz论坛

搭建一个论坛 —接上篇博客 改名/etc/httpd/conf.d/vhosts.conf 》/etc/httpd/conf.d/vhosts.conf.bak [rootlocalhost conf.d]# mv /etc/httpd/conf.d/vhosts.conf /etc/httpd/conf.d/vhosts.conf.bak此时的vhosts.conf是一个新创建的文件&#xff0c;之前的vhosts.conf已经…

使用 Godot 游戏引擎为 Apple 的 visionOS 创建游戏和应用的平台

借助GodotVision ,您可以使用Godot 游戏引擎为 Apple VisionOS创建游戏和应用程序。 保卫牛城堡,一款使用 GodotVision 制作的 VisionOS 游戏 GodotVision 运行一个控制本机RealityKit 视图的无头 Godot实例。粗略地说:Godot 是后端,

毅速3D打印随形透气钢:革新传统,引领未来

透气钢&#xff0c;这种多孔金属材料&#xff0c;既融合了金属材料的坚固性&#xff0c;又具备了透气材料的通透性。尤其在注塑模具的制造中&#xff0c;透气钢的作用不可忽视。通过镶嵌透气钢&#xff0c;能够有效解决因困气产生的注塑问题&#xff0c;使成型加工更为完善&…

【机器学习】机器学习学习笔记 - 监督学习 - 逻辑回归分类朴素贝叶斯分类支持向量机 SVM (可分类、可回归) - 04

逻辑回归分类 import numpy as np from sklearn import linear_modelX np.array([[4, 7], [3.5, 8], [3.1, 6.2], [0.5, 1], [1, 2], [1.2, 1.9], [6, 2], [5.7, 1.5], [5.4, 2.2]]) y np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])# 逻辑回归分类器 # solver&#xff1a;求解器&a…

C字符串操作strlenstrnlen_s详解

前言 strcat、strcpy、strcmp、strlen是C中针对字符串的库函数&#xff0c;这四个函数不安全&#xff0c;然后C针对这个情况整出strcat_s、strcpy_s、strncmp、strnlen_s(这个并不是替代stelen的)来弥补。 这篇文章主要讲&#xff1a;strlen以及strnlen_s的用法。 详见C字符串…

SpringBoot项目整合Knife4j接口文档

文章目录 什么是接口文档&#xff1f;谁用接口文档为什么需要接口文档怎么做接口文档springboot如何整合knife4j?1.引入依赖2.在config目录下创建Knife4j配置依赖3.在appliacation.yml中进行配置4.启动Spring Boot工程&#xff0c;在浏览器中访问&#xff1a;http://localhost…

文件传输服务器是否支持文件的增量备份?

文件传输服务器通常并不直接支持增量备份&#xff0c;因为文件传输服务器的主要功能是提供文件传输服务&#xff0c;而不是备份服务。然而&#xff0c;你可以在文件传输服务器上实现增量备份的功能&#xff0c;方法如下&#xff1a; 使用备份软件&#xff1a;安装并配置专门的备…

机器学习鸢尾花使用csv

操作流程 下载鸢尾花数据集导入需要的包读取数据并查看数据大小和长度划分训练集和测试集使用模型评估算法 下载鸢尾花数据集 链接&#xff1a;https://pan.baidu.com/s/1RzZyXsaiJB3e611itF466Q?pwdj484 提取码&#xff1a;j484 --来自百度网盘超级会员V1的分享导入需要…

【力扣 | 分享】高频 SQL 50 题(基础版)

题单 查询可回收且低脂的产品寻找用户推荐人大的国家文章浏览 I无效的推文 连接使用唯一标识码替换员工ID产品销售分析 I进店却未进行过交易的顾客上升的温度每台机器的进程平均运行时间员工奖金学生们参加各科测试的次数至少有5名直接下属的经理确认率有趣的电影平均售价项目员…

ZCC51215同步降压芯片 输出电流30A

描述&#xff1a; ZCC51215是一颗用于 Notebook 或Desktop的同步降压 控制器。具有 4V 到 24V 的宽输入电压范围&#xff0c;适用于锂 电池或者适配器供电。输出电压可以通过 VID0和 VID1 逻辑信号动态切换&#xff0c;电压切换斜率可以通过 VREF 引脚 的电容进行配置&…

react异步组件如何定义使用 标准使用方法

目录 默认导出和命名导出的格式 默认导出的组件 使用方式 命名导出的组件 使用方式 默认导出和命名导出的格式 默认导出: // person.js const person {name: Alice,age: 30 };export default person;命名导出&#xff1a; // math.js export const add (a, b) > a b; exp…

矩阵混乱度(熵值)代码计算

1、先回顾下熵值的数据公式&#xff1a; 2、jax.numpy代码 注意的点&#xff1a;熵值计算的输入的必须是归一化的正值 import jax.numpy as jnp import jax def _entroy(probs):log_probs jnp.log2(jnp.maximum(1.0e-30, probs))mean_sum_plogp jnp.mean(- jnp.sum(log_pro…

vscode+vue开发常用插件整理

前言&#xff1a; vscode新机开发常用插件整理 1、chinese 简体中文配置 2、file-jump 别名跳转&#xff0c;可以把引入的组件&#xff0c;通过ctrl地址名 跳转组件内部 3、Vue Peek&#xff1a;vue项目中的一些配置&#xff0c;安装后&#xff0c;能实现 ctrl组件名 跳转…

python中用struct打包

Python字节流打包是指将数据按照一定的格式打包成字节流的过程。在Python中&#xff0c;可以使用struct模块来进行字节流的打包和解包操作。 struct模块提供了一些函数&#xff0c;用于将数据转换为特定的字节流格式&#xff0c;或者将字节流解析为特定的数据类型。常用的函数…

Golang图像处理实战:image/png包的应用详解

Golang图像处理实战&#xff1a;image/png包的应用详解 介绍基本操作读取PNG文件保存PNG文件 处理图像数据修改图像像素图像裁剪和缩放 高级功能使用 image/color 处理颜色优化PNG性能 错误处理与调试常见错误及其解决方法文件无法打开图像解码失败 使用工具和库进行调试 结语 …

光流法跟踪

光流法&#xff08;Optical Flow&#xff09;是一种计算机视觉技术&#xff0c;用于估计图像序列中像素点的运动&#xff0c;即在连续两帧或多帧图像间&#xff0c;由于场景中物体的运动而在像素层面产生的相对移动。在目标跟踪场景中&#xff0c;特别是针对关键点的跟踪&#…

测试数据整理--chatgpt 构造sql语句导出数据库数据

在测试过程中&#xff0c;我们有时候需要准备一些测试数据&#xff0c;若从系统中直接导出Excel数据&#xff0c;数据往往庞大且需要整合&#xff0c;不好整理&#xff0c;于是我们直接去数据库中查询一些表&#xff0c;数据整合后直接导出结果会更方便。 我们今天就 用 chatg…

shell 调用钉钉通知

使用场景&#xff1a;机器能访问互联网&#xff0c;运行时间任务后通知使用 钉钉建立单人群 手机操作&#xff0c;只能通过手机方式建立单人群 电脑端 2. 配置脚本 #!/bin/bash set -e## 上图中 access_token字段 TOKEN KEYWORDhello # 前文中设置的关键字 function call_…