pnpm 分析总结

一、安装

npm i -g pnpm

二、特性

  1. 速度快
  2. 高效使用磁盘空间
  • pnpm 内部使用基于内容寻址的文件系统来存储磁盘上所有的文件,这个文件系统出色的地方在于:
  • 不会重复安装同一个包。用 npm/yarn 的时候,如果 100 个项目都依赖 lodash,那么 lodash 很可能就被安装了 100 次,磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm
    只会安装一次,磁盘中只有一个地方写入,后面再次使用都会直接使用 hardlink。symlink和hardlink机制 (软链接和硬链接)
  • 即使一个包的不同版本,pnpm 也会极大程度地复用之前版本的代码。举个例子,比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的
    hardlink,仅仅写入那一个新增的文件。
  1. 对monorepo的支持
  1. 安全性
  • 安全 pnpm通过特殊文件,来对包含所有已安装软件包进行校验,保证软件包的完整性。
  1. 离线模式,将所有下载的包保存在本地注册表镜像中。当本地可用就不用发送http请求

三、依赖管理

  1. npm yarn v1 流程
  • 将依赖包的版本区间解析为某个具体的版本号
  • 下载对应版本依赖的 tar 包到本地离线镜像
  • 将依赖从离线镜像解压到本地缓存
  • 将依赖从缓存拷贝到当前目录的 node_modules 目录
node_modules
└─ foo
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ bar
         ├─ index.js
         └─ package.json
  1. npm yarn v1 缺陷
  • 依赖层级太深,会导致路径过程,win更加明显
  • 大量包被重复安装,文件体积过大。许多包都依赖其中一个工具的依赖包
  • 模块实例不能共享。React内部变量,在两个不同包引入的 React 不是同一个模块实例,因此无法共享内部变量,导致一些不可预知的 bug。
  1. npm v3版本
  • 引入扁平化依赖管理
  • 所有的依赖都被拍平到node_modules目录下,不再有很深层次的嵌套关系。这样在安装新的包时,根据 node require
    机制,会不停往上级的node_modules当中去找,如果找到相同版本的包就不会重新安装,解决了大量包重复安装的问题,而且依赖层级也不会太深。
node_modules
├─ foo
|  ├─ index.js
|  └─ package.json
└─ bar
   ├─ index.js
   └─ package.json
  1. yarn和npm v3 同样使用了扁平化的node_module结构,但是也带来许多问题。
  • 模块可以访问他们不依赖的包
  • 扁平化依赖关系树的算法十分复杂
  • 某些包必须复制一个项目的node_modules文件夹
  • 硬盘空间问题
  1. pnpm
  • 通过软连接方式去获取本地仓库store里面包,节省空间,防止Phantom dependencies(幽灵依赖)和 NPM doppelgangers (npm 二重身)

四、symlink和hardlink机制 (软链接和硬链接)

  1. hardlink和symlink区别
  • hardlink仅能链接文件,而symlink可以链接目录
  • hardlink在链接完成后仅和文件内容关联,和之前链接的文件没有任何关系。而符号链接始终和之前链接的文件关联,和文件内容不直接相关
  1. 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 二重身)

  1. Phantom dependencies
  • packge.json
    没有这个问题但是用户却能用到这个包。主要是node_modules结构的问题,主要是依赖里面有foo,然后foo又依赖了bar,然后yarn对安装进行扁平化结构处理,会把node_modules进行打平foo和bar出现在同一层级根据node寻径原理,用户能require到foo也能require到bar,这就导致幽灵依赖,如果哪天版本变动,那个包版本变动就会导致报错。在pnpm就不会存在这种问题,他会在虚拟磁盘去寻找,用户required不到。
  1. 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可能出现的问题

  1. pnpm 对Electron存在问题 出现符号链接问题。
  1. pnpm store 问题 本地包体积过大
  • pnpm会下载包保存在本地,时间长了导致本地store文件过大,可以通过减少重复不被引入的包的方式 foo@0.01 foo@1.0.0 你可以通过pnpm store prune
    来清理无用的包,当再次需要他们重新下载。不建议过于频繁。
posted @   爱好跑步的小张  阅读(992)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示