pnpm 分析总结
一、安装
npm i -g pnpm
二、特性
- 速度快
- 高效使用磁盘空间
- pnpm 内部使用基于内容寻址的文件系统来存储磁盘上所有的文件,这个文件系统出色的地方在于:
- 不会重复安装同一个包。用 npm/yarn 的时候,如果 100 个项目都依赖 lodash,那么 lodash 很可能就被安装了 100 次,磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm
只会安装一次,磁盘中只有一个地方写入,后面再次使用都会直接使用 hardlink。symlink和hardlink机制 (软链接和硬链接) - 即使一个包的不同版本,pnpm 也会极大程度地复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的
hardlink,仅仅写入那一个新增的文件。
- 对monorepo的支持
- 安全性
- 安全 pnpm通过特殊文件,来对包含所有已安装软件包进行校验,保证软件包的完整性。
- 离线模式,将所有下载的包保存在本地注册表镜像中。当本地可用就不用发送http请求
三、依赖管理
- npm yarn v1 流程
- 将依赖包的版本区间解析为某个具体的版本号
- 下载对应版本依赖的 tar 包到本地离线镜像
- 将依赖从离线镜像解压到本地缓存
- 将依赖从缓存拷贝到当前目录的 node_modules 目录
node_modules
└─ foo
├─ index.js
├─ package.json
└─ node_modules
└─ bar
├─ index.js
└─ package.json
- npm yarn v1 缺陷
- 依赖层级太深,会导致路径过程,win更加明显
- 大量包被重复安装,文件体积过大。许多包都依赖其中一个工具的依赖包
- 模块实例不能共享。React内部变量,在两个不同包引入的 React 不是同一个模块实例,因此无法共享内部变量,导致一些不可预知的 bug。
- npm v3版本
- 引入扁平化依赖管理
- 所有的依赖都被拍平到node_modules目录下,不再有很深层次的嵌套关系。这样在安装新的包时,根据 node require
机制,会不停往上级的node_modules当中去找,如果找到相同版本的包就不会重新安装,解决了大量包重复安装的问题,而且依赖层级也不会太深。
node_modules
├─ foo
| ├─ index.js
| └─ package.json
└─ bar
├─ index.js
└─ package.json
- yarn和npm v3 同样使用了扁平化的node_module结构,但是也带来许多问题。
- 模块可以访问他们不依赖的包
- 扁平化依赖关系树的算法十分复杂
- 某些包必须复制一个项目的node_modules文件夹
- 硬盘空间问题
- pnpm
- 通过软连接方式去获取本地仓库store里面包,节省空间,防止Phantom dependencies(幽灵依赖)和 NPM doppelgangers (npm 二重身)
四、symlink和hardlink机制 (软链接和硬链接)
- hardlink和symlink区别
- hardlink仅能链接文件,而symlink可以链接目录
- hardlink在链接完成后仅和文件内容关联,和之前链接的文件没有任何关系。而符号链接始终和之前链接的文件关联,和文件内容不直接相关
- pnpm链接依赖流程
- pnpm 是通过 hardlink 在全局里面 store 目录来存储 node_modules 依赖里面的 hardlink 地址,然后在引用依赖的时候则是通过 symlink 去找到对应虚拟磁盘目录下(.pnpm 目录)的依赖地址。
- 一般 store 目录默认是设置在 ${os.homedir}/.pnpm-store 这个目录下
node_modules
└── bar // symlink to .pnpm/bar@1.0.0/node_modules/bar
└── foo // symlink to .pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
│ ├── index.js
│ └── package.json
└── foo@1.0.0
└── node_modules
└── foo -> <store>/foo
├── index.js
└── package.json
五、对于Monorepo解决了 Phantom dependencies(幽灵依赖) 和 NPM doppelgangers (npm 二重身)
- Phantom dependencies
- packge.json
没有这个问题但是用户却能用到这个包。主要是node_modules结构的问题,主要是依赖里面有foo,然后foo又依赖了bar,然后yarn对安装进行扁平化结构处理,会把node_modules进行打平foo和bar出现在同一层级根据node寻径原理,用户能require到foo也能require到bar,这就导致幽灵依赖,如果哪天版本变动,那个包版本变动就会导致报错。在pnpm就不会存在这种问题,他会在虚拟磁盘去寻找,用户required不到。
- NPM doppelgangers
- 这个问题其实是hoist导致的。大量依赖被重复安装。
- 例如有个 package,下面依赖有 lib_a、lib_b、lib_c、lib_d,其中 a 和 b 依赖 util_e@1.0.0,而 c 和 d 依赖 util_e@2.0.0。
- package
- package.json
- node_modules
- lib_a
- node_modules <- util_e@1.0.0
- lib_b
- node_modules <- util_e@1.0.0
_ lib_c
- node_modules <- util_e@2.0.0
- lib_d
- node_modules <- util_e@2.0.0
- 这样必然会导致很多依赖被重复安装,于是就有了 hoist 和打平依赖的操作:
- package
- package.json
- node_modules
- util_e@1.0.0
- lib_a
- lib_b
_ lib_c
- node_modules <- util_e@2.0.0
- lib_d
- node_modules <- util_e@2.0.0
-
但是这样也只能提升一个依赖,如果两个依赖都提升了会导致冲突,这样同样会导致一些不同版本的依赖被重复安装多次,这里就会导致使用 npm 和 yarn 的性能损失。
-
如果是 pnpm 的话,这里因为依赖始终都是存在 store 目录下的 hard links ,一份不同的依赖始终都只会被安装一次,因此这个是能够被彻彻底底的消除的。
六、pnpm可能出现的问题
- pnpm 对Electron存在问题 出现符号链接问题。
- pnpm store 问题 本地包体积过大
- pnpm会下载包保存在本地,时间长了导致本地store文件过大,可以通过减少重复不被引入的包的方式 foo@0.01 foo@1.0.0 你可以通过pnpm store prune
来清理无用的包,当再次需要他们重新下载。不建议过于频繁。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!