[PNPM] 其他包管理器

news/2025/4/19 3:30:33/文章来源:https://www.cnblogs.com/Answer1215/p/18790508

Yarn

Yarn 这个包管理器是在 2016 的时候由 Facebook、Google、Exponent 以及 Tilde 团队共同开发推出的。

image-20240822104204072

当时 Yarn 的出现主要是为了解决 npm 在速度安全性以及一致性方面的一些问题:

  • 安装速度

  • 确定性:

    • 项目A ---> 直接依赖: libraryX(1.0)-----> 间接依赖:libraryY(1.3)
    • 项目A ---> 直接依赖: libraryX(1.0)-----> 间接依赖:libraryY(2.0)
    • Yarn 引入了一个 yarn.lock 锁文件
  • 安全性

  • 离线安装

指令对比:

npm Yarn 说明
npm init yarn init 初始化项目
npm install/link yarn install/link 默认的安装依赖操作
npm install <package> yarn add <package> 安装某个依赖
npm uninstall <pacakge> yarn remove <package> 移除某个依赖
npm install <package> --save-dev yarn add <pacakge> --dev 安装开发依赖
npm update <package> --save yarn upgrade <package> 更新某个依赖
npm install <package> --global yarn global add <pacakge> 全局安装
npm publish/login/logout yarn publish/login/logout 发布/登录/登出
npm run <script> yarn run <script> 执行 script 命令

Yarn 的出现让 npm 团队也感受到了压力,做出了一定的改变。

例如从 npm v5 开始引入了名为 package-lock.json 的锁文件,类似于 Yarn 的 yarn.lock 文件。这确保了在不同环境中的依赖结构一致性。

思考🤔:package.json 和 package-lock.json 都是 npm 用于管理项目依赖的文件,两者有什么不同呢?

答案:package.json包描述文件,会包含直接依赖以及元数据信息,package-lock.json 包含所有的依赖信息(包含直接依赖和间接依赖)。

pnpm

在 Yarn 之后,又出现了 pnpm包管理器

pnpm 的优势主要表现在这么 3 个地方:

  1. 节省磁盘空间
  2. 解决幽灵依赖
  3. 原生支持Monorepo

1. 节省磁盘空间

使用 npm 时,如果你有 100 个项目都使用同一个依赖项,你会在磁盘上保存该依赖项的 100 份副本。而使用 pnpm,依赖项会存储在一个内容可寻址的存储中。

16852383061314

pnpm中有两个比较重要的概念:

  • 硬链接
  • 符号链接

硬链接

是指多个文件名指向同一个物理文件数据块。这意味着,无论你通过哪个硬链接访问文件,看到的内容都是相同的。删除一个硬链接不会影响其他硬链接,只有当所有硬链接都被删除后,文件数据才会真正从硬盘中移除

image-20240828083651411

符号链接

符号链接是一个特殊的文件,包含了指向另一个文件或目录的路径。它类似于快捷方式,访问符号链接时,操作系统会将其重定向到实际文件或目录。符号链接本身占用少量空间,但它指向的文件或目录仍然占据实际存储空间。

image-20240828083944364

在 pnpm 中,直接依赖使用硬链接,而间接依赖使用符号链接。下面来做一个和 npm 安装包的对比:

两个项目 ProjectA 和 ProjectB,它们都依赖同一个库 libraryX。

传统的 npm 安装方式

ProjectA 和 ProjectB 都会在各自的 node_modules 文件夹中创建一个独立的 libraryX 目录,并且这些目录里包含了相同的文件内容。即使 libraryX 的版本完全相同,它们仍然会各自占用磁盘空间。

# 安装依赖
cd ProjectA
npm install libraryXcd ../ProjectB
npm install libraryX# 结果:
# ProjectA/node_modules/libraryX/ -> 这是一个完整的libraryX文件
# ProjectB/node_modules/libraryX/ -> 这是另一个完整的libraryX文件

这样,libraryX 的文件在磁盘上被重复存储了两次,即使它们的内容完全一样。

pnpm 使用硬链接的方式

当你使用 pnpm 安装 libraryX 时,pnpm 会将 libraryX 的文件存储在一个全局的内容地址存储(例如 ~/.pnpm-store)中,而不是在每个项目中都完整复制一份。

然后,pnpm 会为 ProjectA 和 ProjectB 中的 libraryX 创建硬链接。硬链接指向全局存储中的同一个物理文件,因此即使在 ProjectA 和 ProjectB 中都有 libraryX 的文件,这些文件在磁盘上只存储了一次。

# 使用 pnpm 安装依赖
cd ProjectA
pnpm install libraryXcd ../ProjectB
pnpm install libraryX# 结果:
# ~/.pnpm-store/libraryX/ -> 这是libraryX的实际物理文件,存储在全局内容地址存储中
# ProjectA/node_modules/libraryX/ -> 这是指向全局存储的硬链接
# ProjectB/node_modules/libraryX/ -> 这是另一个指向全局存储的硬链接

符号链接的使用

pnpm 在处理间接依赖时,会使用符号链接。

例如,假设 libraryX 本身依赖 libraryY,而 libraryY 也存储在全局内容地址存储中。此时 pnpm 会在 libraryX 中创建一个符号链接,指向全局存储中的 libraryY,而不是将 libraryY 的文件直接复制到 libraryX 中。这进一步减少了文件的重复存储。

# 符号链接示例:
# ProjectA/node_modules/libraryX/node_modules/libraryY -> 这是一个符号链接,指向全局存储中的libraryY

思考🤔:如果不同的项目依赖同一个包(libraryX)的不同版本,应该怎么处理?

答案:在全局仓库下分别存储每个版本的 libraryX. 但是这里有一个优化,仅存储不同版本之间不同的文件。

实战演练

使用 pnpm create vue@latest 命令分别创建两个 Vue 项目,查看依赖结构。

pnpm store path

2. 解决幽灵依赖

所谓幽灵依赖,是指当一个包(A)依赖于另一个包(B)时,后者会被放置在前者的 node_modules 目录中。这意味着一个包可能会意外地访问并使用另一个包的依赖,即使它没有在自己的 package.json 文件中声明这些依赖。

实战演练

演示 npm 和 pnpm 对于幽灵依赖的处理。

幽灵依赖会存在的问题:

  1. 难以理解的依赖关系
  2. 潜在的错误

3. 原生支持Monorepo

目前企业中搭建 Monorepo 项目方案,常见有这么几种:

  1. Lerna
  2. Yarn + Workspace
  3. pnpm + Workspace

4. 相关指令

  • 安装 pnpm:可以使用 npm 或者 yarn 进行安装,npm install -g pnpm
  • 创建新项目:pnpm init
  • 添加依赖:pnpm add <package>
  • 添加所有依赖:pnpm install
  • 升级依赖:pnpm update <package>
  • 删除依赖:pnpm remove <package>

包的隔离和提升

这是一张来自于 pnpm 官方给出的和其他包管理器之间的 对比图,如下:

image-20240821101002639

pnpm 默认策略是包隔离,老牌的 npm 的默认策略是包提升

  • 包隔离:是指在项目中,每个依赖包都有自己独立的安装环境,这样可以避免不同依赖之间的冲突。这个概念尤其重要,当不同的依赖包需要相同的子依赖但不同版本时,如果没有良好的隔离机制,就可能导致依赖版本冲突,进而导致项目运行错误或行为异常。
  • 包提升:是指将依赖关系中某些包提升到更高的目录层次,以减少冗余,节省磁盘空间

示例:假设我们有一个项目 MyApp,该项目依赖两个包 PackageA 和 PackageB(这两个包是直接依赖),这两个包又有相同的间接依赖:

  • PackageA 依赖 lodash@4.17.21
  • PackageB 依赖 lodash@3.10.1

在没有包隔离的情况下,传统的包管理工具(例如 npm 早期版本)可能会尝试将 lodash 的一个版本提升到项目的 node_modules 根目录。如果 lodash@4.17.21 被安装在根目录下,那么 PackageB 依赖的 lodash@3.10.1 就会被忽略,导致 PackageB 无法正常运行。

而 pnpm 默认采用的就是包隔离策略,自然不存在上面的问题。

思考🤔:包提升本质上是为了节省磁盘空间,pnpm 采用包隔离的话磁盘空间会有浪费么?

答案:不会,因为pnpm有全局的存储空间,最终不同版本的依赖都是存储在全局空间里面,本地项目通过硬链接连接到对应版本的包。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/905103.html

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

相关文章

3.24 位运算,哈希,前缀

题目链接 题目背景 我们需要解决的问题是:给定一个整数数组 nums 和两个整数 low 和 high,统计满足条件的“漂亮数对” (i, j) 的数量,其中: 0 <= i < j < nums.length low <= (nums[i] XOR nums[j]) <= high 简单来说,我们要找所有满足条件的数对 (i, j),…

Kioptrix Level_1

Kioptrix Level 1.1 靶场配置 导入靶场时先将vmx后缀文件中的带有ethernet0的配置行全部删除,再导入靶场,添加一个网络适配器即可 信息收集 查找目标主机ip ┌──(root㉿kali)-[~] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:84:b2:cc, IPv4: 192.168…

selenium之八大定位

八大定位 今天我们来学一学,selenium有名的八大定位方式;都有哪八个呢,下面我先列出来;之后再一个一个的实践id,通过id定位元素 name,通过name定位 class_name,通过class类名定位 tag_name,通过标签名称 link_text,通过链接文本 partial_link_text,通过部分链接文本 …

NAS配置iCloudpd

附上链接【教程】使用icloudpd自动同步iCloud照片 纠正两个错误: 1)sync-icloud.sh --Initialise 原文写的是sync-icloud.sh –Initialise是错误的,现在的版本应该如上 需要-- 不然你就会反复出现2分钟后重试的问题 2)文中的 *** 这步很重要!!!成功后,你会发现 config …

滴滴数据仓库工程师面试题

‌一、数据仓库基础与建模‌‌数仓分层设计‌请描述滴滴数仓分层架构及各层核心作用(如ODS、DWD、DWS、ADS)‌。 ‌1. ODS(Operational Data Store)层:原始数据层‌‌数据内容‌:直接从业务系统抽取的原始数据,包括订单流水、用户行为日志、司机接单记录、GPS轨迹等。‌…

20244209韩仕炜《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2442 姓名:韩仕炜 实验教师:王志强 学号:20244209 实验日期:2025年3月24日 必修/选修:专选课 1. 实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能; 3.编写程序,练习变量和类型、字符串、对象、缩进和注释等; 4.编写一…

E1. Canteen (Easy Version)E2 Canteen (Hard Version) 对于旋转操作的深入理解

E1. Canteen (Easy Version) 题解:二分查找 + 模拟 本文大量学习了jiangly的代码对其进行详细的解析并作图对其进行解释 题目链接 深入解析:前缀和最小值旋转的直观意义一、前缀和曲线的数学本质 我们定义前缀和数组为: pre[i+1] = pre[i] + a[i] - b[i]这一公式的物理意义是…

20244209 2024-2025-2 《Python程序设计》实验一报告

课程:《Python程序设计》 班级: 2442 姓名:韩仕炜 实验教师:王志强 学号:20244209 实验日期:2025年3月24日 必修/选修:专选课 1. 实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能; 3.编写程序,练习变量和类型、字符串、对象、缩进和注释等; 4.编写一…