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

news2024/11/19 6:30:47

一、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.Empty
		case 1: {
			const c0 = p.charCodeAt(0);
			switch (c0) {
				case CHAR_DOT:
					return PathType.Relative; // 如果开头的第一个字符为‘.’时,返回PathType.Relative
				case CHAR_SLASH:
					return PathType.AbsolutePosix; // 如果开头的第一个字符为‘/’时,返回PathType.AbsolutePosix
				case 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.AbsolutePosix
				case 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.Relative
				case CHAR_DOT: {
					const c2 = p.charCodeAt(2);
					if (c2 === CHAR_SLASH) return PathType.Relative; // 当第一个字符为‘.’第二个字符为‘.’和第三个字符为‘/’时,返回PathType.Relative
					return PathType.Normal; // 没有匹配到返回兜底值PathType.Normal
				}
			}
			return PathType.Normal;// 没有匹配到返回兜底值PathType.Normal
		}
		case CHAR_SLASH:
			return PathType.AbsolutePosix; // 当第一个字符为‘/’时,返回PathType.AbsolutePosix
		case 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.coloradmin.cn/o/1610225.html

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

相关文章

颠覆传统消费,走向可持续:每次购物都是循环的开始

亲爱的读者朋友们&#xff0c;大家好&#xff0c;我是微三云周丽。今天&#xff0c;我非常激动地想要向大家分享一种极具创新性和前瞻性的商业模式——循环购。这种模式将消费返利与积分返利理念相融合&#xff0c;为商家与消费者之间搭建了一座互动与共赢的桥梁&#xff0c;让…

安全开发实战(1)--Cdn

目录 安全开发专栏 CDN介绍 1.信息收集阶段 1.1判断CDN是否存在 1.1.1, One 1.1.2,Two(改进) 1.1.3,进行整合 增加输入功能 1.1.4 批量读取监测存储(进行测试) 问题1: 问题2: 解决方案: 1.1.4 基本编写完成 命令框中: cdn存在.txt 总结 这里我是根据整个渗透测…

【spring】springProperty 使用

springProperty 是一个在 Spring 框架中使用的SpEL&#xff08;Spring Expression Language&#xff09;表达式&#xff0c;它允许你在应用程序的配置中引用 Spring 应用程序上下文中的属性值。这个表达式通常用于从 Spring 的 Environment 对象中获取配置属性的值&#xff0c;…

【Java探索之旅】用面向对象的思维构建程序世界

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、初识面向对象1.1 什么是面向对象&#xff1f;1.2 面向对象与面向过程 二、类的定义…

HDLbits 刷题 -- Adder100

Create a 100-bit binary adder. The adder adds two 100-bit numbers and a carry-in to produce a 100-bit sum and carry out. 译&#xff1a; 创建一个100位二进制加法器。加法器将两个100位的数字和一个进位相加&#xff0c;产生一个100位的和并执行。 个人解法&#xf…

短视频素材哪里去找?推荐几个视频素材免费下载的网站

高质量的资源&#xff0c;会让你的视频创作更加生动和具有吸引力。下面我为你介绍世界各地的优质无水印视频素材网站&#xff0c;以拓宽你的创作视野&#xff0c;帮助你在这个视觉革命的时代中脱颖而出。 1. 蛙学府&#xff08;中国&#xff09; 提供各种类别的优质高清视频素…

【Linux C | 多线程编程】互斥量、信号量、条件变量对比总结

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 本文未经允许…

【UKE!】2024.4.19

2024.4.19 【你知道的都是真相。只可惜那些并不是真相的全部。】 Friday 三月十一 谷雨 <BGM “谷雨–音阙诗听”> AC :Answer Coarse,粗劣的答案 ​ CE :Compile Easily,轻松通过 ​ PC :Perfect Compile 完美的编译 ​ WA :Wonderful Answer,好答案 ​ RE :Run Exce…

【Java开发指南 | 第十六篇】Java数组及Arrays类

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 数组数组特点创建数组处理数组多维数组Arrays类 数组 Java中的数组是一种用来存储固定大小的相同类型元素的数据结构。 数组特点 数组具有以下特点&#xff1a; 1、固定大小: 一旦数组被创建&#xff0c;其…

【云计算】云数据中心网络(五):对等连接

《云网络》系列&#xff0c;共包含以下文章&#xff1a; 云网络是未来的网络基础设施云网络产品体系概述云数据中心网络&#xff08;一&#xff09;&#xff1a;VPC云数据中心网络&#xff08;二&#xff09;&#xff1a;弹性公网 IP云数据中心网络&#xff08;三&#xff09;…

vue3 echarts 图表主题切换

我主要是用了localStorage和composable来实现的。 先创建composable文件夹存储composable的操作方法&#xff1b; 在App.vue文件里面&#xff0c;先将主题数据存储在localStorage里面&#xff1b; 主题切换 图表theme包更换 为什么要用composable呢&#xff1f; 单纯的使用…

CS61B sp21fall Project02 Gitlet

Project02 Gitlet 一、项目简介二、Git和Gitlet2.1 Git简介2.2 Gitlet简介 三、框架设计3.1 Blobs3.2 Trees3.3 Commits 四、.Gitlet文件结构设计4.1 .git文件架构4.1.1 重点介绍index&#xff08;VSCode中无法查看&#xff0c;会乱码&#xff09;objects&#xff08;VSCode中无…

【汇编语言】初识汇编

【汇编语言】初识汇编 文章目录 【汇编语言】初识汇编前言由机器语言到汇编语言机器语言与机器指令汇编语言与汇编指令汇编语言程序示例 计算机组成指令和数据的表示计算机的存储单元计算机的总线 内存读写与地址空间CPU对存储器的读写内存地址空间 总结 前言 为什么要学习汇编…

精通MongoDB聚合操作API:深入探索高级技巧与实践

MongoDB 聚合操作API提供了强大的数据处理能力&#xff0c;能够对数据进行筛选、变换、分组、统计等复杂操作。本文介绍了MongoDB的基本用法和高级用法&#xff0c;高级用法涵盖了setWindowFields、merge、facet、expr、accumulator窗口函数、结果合并、多面聚合、查询表达式在…

动态库静态库linux

动态库静态库 静态库 静态库必须包含在可执行文件里&#xff0c;整个都要包含 缺点&#xff1a;消耗系统大&#xff0c;每个使用静态库的程序都要复制静态库&#xff08;浪费内存&#xff09; 影响使用场景&#xff1a; 在静态库内存小的时候&#xff0c;可以用来提升速度 制…

Linux(CentOS7)离线使用安装盘部署Telnet

# [pdf在线免费转word文档](https://orcc.online/pdf) https://orcc.online/pdf 挂载镜像CentOS-7-x86_64-DVD-1810.iso到/mnt下&#xff08;其他位置也行&#xff09;&#xff0c;命令如下&#xff1a; mount /dev/sr0 /mnt 安装包默认在Packages目录下&#xff0c;需要安装…

【QT进阶】Qt Web混合编程之CMake VS2019编译并使用QCefView(图文并茂超详细版本)

往期回顾 【QT进阶】Qt Web混合编程之CEF、QCefView简单介绍-CSDN博客 【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用&#xff08;图文并茂超详细介绍&#xff09;-CSDN博客【QT进阶】Qt Web混合编程之QWebEngineView基本用法-CSDN博客【QT进阶】Qt Web混合编程之VS2019 C…

AI生图美学在淘宝的实践应用

本文介绍了如何制定和应用美学标准来评估和改善人工智能生成的图像质量&#xff0c;特别是在电商领域的应用&#xff0c;主要分为制定美学标准、训练美学模型、应用美学模型、升级淘宝风格模型四个步骤。 美学的定义与分析 图像质量标准&#xff1a;现代设计框架下&#xff0c;…

类和对象【二】this指针,构造函数和成员初始化列表【超详细】

文章目录 this指针this指针的定义this指针的“工作”原理this指针的作用this指针的特点 构造函数构造函数的定义构造函数的作用构造函数的特点构造函数的调用方式括号法无参构造或者全缺省构造需要传参才能调用的构造函数 隐式类型转换法是只传一个参数就能调用的构造函数是要传…

HCIE-Shell实验1

要求&#xff1a; 判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检查一次磁盘剩余空间。判断web服务是否运行(1、査看进程的方式判断该程序是否运行&#xff0c;2、通过查看端口的方式判断该程序是否运行)&…