首页 > 其他分享 >pnpm 对比 npm 的改变

pnpm 对比 npm 的改变

时间:2022-11-30 23:11:39浏览次数:52  
标签:npm node 依赖 路径 modules 对比 pnpm 链接

简介

pnpm 相比 npm 提高了安装速度、降低了存储空间,这得益于其在路径结构和存储方式上所做的改进。

pnpm 解决的问题:

  • /.pnpm 路径的存在解决了“幽灵依赖”问题(或者可以称为隐形依赖,也就是未在 package.json 中声明,但代码中引用了某个依赖包;一开始看到这个词还以为是指项目已经不再依赖某个包了,但包还在硬盘的全局仓库中保存着,毕竟依赖包实际并不是保存在项目路径下了,在项目层面删除依赖并不会影响全局的依赖包文件)
  • “顶层打平+嵌套依赖的依赖” 的结构
    • 解决了“依赖分身”问题:多个依赖包继续依赖某个依赖的不同版本,导致部分版本需要重复安装
    • 同时这种结构又避免了早期的包管理器对“依赖的依赖”全部嵌套带来的文件夹路径过长问题。比如:项目 app 依赖 moduleA,而 moduelA 依赖 moduleB,moduelB 又依赖 moduelC,这就已经存在 3 层依赖了,从文件夹来看就是 6 层嵌套,算上 app 本身的路径就更长了

依赖结构

pnpm 在顶层与 npm 新版类似,打平了所有的依赖包;但具体到各个依赖的目录中,还是会嵌套保存各自的依赖包关系。

同时, pmpm 将顶层的依赖项多嵌套了一层 /.pnpm,也就是所有依赖实际的是在 /node_modules/.pmpm 路径下,这样就避免了“幽灵依赖”的问题。

链接与统一存储

npm 都是根据项目维度将所有依赖保存在项目路径下,不仅不同项目对于同一个版本的依赖会重复安装,甚至一个项目下的不同依赖间,继续存在相同依赖时也会重复安装,导致大量空间的浪费。

而 pnpm 是将所有依赖同一保存在某个位置,也就是全局安装。项目只是引用了这个全局位置中的实际依赖包,而不是直接复制一份,因此有效降低了重复的依赖。

软链接(符号链接)与硬链接

软链接和硬链接是来自于 Linux 系统的概念,是两种特殊的文件。

软链接可以看做是文件的快捷方式,与源文件是两个独立的文件;而硬链接在系统层面上其实是一个文件。这是因为软链接保存的是源文件的地址,而硬链接保存的就是文件在系统中的编号(inode,通过这个 inode 编号可以获取硬盘上的实际数据)。因此,通过硬链接可以直接获取源文件的内容,而通过软链接只能获取到源文件,还需要通过源文件进一步获取其编号才能得到真实内容。

打个不恰当的比方:有个人找朋友借钱,朋友会从卡里取钱然后借给他;但这个人不能直接从朋友的卡里拿钱。前者相当于软链接,后者相当于硬链接。硬链接享有数据的控制权,而软链接不行。

层级结构示例

以下示例取自官网:

node_modules
├── foo -> ./.pnpm/[email protected]/node_modules/foo
└── .pnpm
├── [email protected]
│ └── node_modules
│ ├── bar -> /bar
│ └── qar -> ../../[email protected]/node_modules/qar
├── [email protected]
│ └── node_modules
│ ├── foo -> /foo
│ ├── bar -> ../../[email protected]/node_modules/bar
│ └── qar -> ../../[email protected]/node_modules/qar
└── [email protected]
└── node_modules
└── qar -> /qar

分析:

  • /node_moduels 是根路径不变
    • 根路径下,项目的直接依赖(package.json 中声明的依赖项)会各自生成一个软链接文件,指向 /.pnpm 路径下的对应硬链接文件
    • 根路径下,/.pnpm 目录下,是项目中所有直接依赖以及依赖的间接依赖
      • 直接依赖对应的路径是 /.pnpm/<name>@<version>/node_modules/<name> (其中 name 表示一个依赖包的名字),此文件为硬链接,指向 pnpm 实际在硬盘中的存储地址
      • 间接依赖也是在各依赖的 /.pnpm/<name>@<version>/node_modules/ 路径下,但这些文件都是软链接,引用了 /.pnpm 路径下的实际硬链接文件

总结:除了各 /.pnpm/<name>@<version>/node_modules/<name> 文件是硬链接外,其他依赖文件都是软链接。如果把项目中的依赖文件跟全局依赖比作前后端,则硬链接相对于 API ,它们可以直接与全局依赖包文件进行链接;而软链接相当于在各个模块中调用了 API ,通过 API 间接获取全局的实际依赖包文件。

至于为什么要保留硬链接而不是全部使用软链接,似乎与 Node.js 的路径解析模块有关,但具体的原因还没看懂,只知道软链接在 Node.js 中可能会先找到依赖的实际存储路径,此时若没有使用 --preserve-symlinks,Node.js 解析模块路径时会从实际路径出发找依赖项,则根据依赖的相对路径解析就可能失败。

以下是作者对该问题的讨论:https://github.com/nodejs/node-eps/issues/46

标签:npm,node,依赖,路径,modules,对比,pnpm,链接
From: https://www.cnblogs.com/cjc-0313/p/16940127.html

相关文章