本文引用自 摸鱼wiki
1. 与npm,yarn性能比较
action | cache | lockfile | node_modules | npm | pnpm | Yarn | Yarn PnP |
---|---|---|---|---|---|---|---|
install | 33.8s | 20.1s | 20.3s | 40.7s | |||
install | ✔ | ✔ | ✔ | 2.1s | 1.4s | 2.6s | n/a |
install | ✔ | ✔ | 9.1s | 5.3s | 7.8s | 1.7s | |
install | ✔ | 13.5s | 9.3s | 14.1s | 7.7s | ||
install | ✔ | 15s | 17.2s | 14.2s | 33.4s | ||
install | ✔ | ✔ | 2.5s | 3s | 8.8s | n/a | |
install | ✔ | ✔ | 2s | 1.4s | 8.7s | n/a | |
install | ✔ | 2.5s | 11.2s | 14.7s | n/a | ||
update | n/a | n/a | n/a | 8.9s | 12s | 6.9s | 14.9s |
2. 基于符号链接的node_modules文件组织架构
下图摘自官网,基本说明了 pnpm 的文件组织以及运行方式。
pnpm 会统一管理整个系统安装的项目包,并将其统一保存在名为 .pnpm-store 的文件夹内。对于一个新项目来说,项目的 node_modules 由多个依赖库 + .pnpm 组成。pnpm 会将项目依赖包以 包名@版本号 命名的文件夹的形式平铺在项目的 .pnpm 文件夹内,而每个文件夹内部的 node_modules 则会存储库自身及其依赖库。其中,库自身以硬链接的方式指向 .pnpm-store 文件夹内的同名同版本库(图中的红色虚线),并在项目的 node_modules 下创建同名同版本的软链接(图中的绿色实线);库的前置依赖则会以软链接的方式指向当前项目的 .pnpm 文件夹下的同名同版本库(图中的黄色实线)。
图中的实例为了展示库的版本号,可能与实际的目录结构有所偏差。实际上对于项目的 node_modules 的库,为了保持兼容性,是没有版本号的后缀的。最后的目录结构可以参考下面的代码:
node_modules
├── bar -> ./.pnpm/bar@1.0.0/node_modules/bar
└── .pnpm
├── foo@1.0.0
│ └── node_modules
│ └── foo -> <store>/foo
└── bar@1.0.0
└── node_modules
├── bar -> <store>/bar
└── foo -> ../../foo@1.0.0/node_modules/foo
3. 解决 peers
那这时候有个问题,如果项目中多个库有相同的前置依赖库,但各自依赖的版本不一样,会怎么样?
这个问题npm曾经解决过,他的解决方法是先安装的依赖库版本平铺在项目的 node_modules 文件夹内,后续安装的写在依赖该库的 node_modules 文件夹内,形如:
// bar
{
"dependencies": {
"baz": "2.0.0"
}
}
// foo
{
"dependencies": {
"baz": "1.0.0"
}
}
node_modules
├── bar
│ └── node_modules
│ └── baz@2.0.0
├── foo
└── baz@1.0.0
但这样存在一个问题,如果后续有个库quz依赖 baz@2.0.0,这种情况下 baz@2.0.0 会在quz目录下重新再次安装,浪费磁盘空间。而在pnpm下,所有的依赖库都是以硬链接 + 软链接的方式组织,全局只保留一份代码,因此不会有这个问题。
node_modules
├── bar -> ./.pnpm/bar@1.0.0/node_modules/bar
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── foo@1.0.0
│ └── node_modules
│ ├── foo -> <store>/foo
│ └── baz -> ../../baz@1.0.0/node_modules/baz
├── bar@1.0.0
│ └── node_modules
│ ├── bar -> <store>/bar
│ └── baz -> ../../baz@2.0.0/node_modules/baz
├── baz@1.0.0
└── baz@2.0.0
更多例子可以查看 how-peers-are-resolved
4. yarn,npm迁移到pnpm
官网有对应的解决方法,使用 pnpm import 从另一个软件包管理器的 lock 文件生成 pnpm-lock.yaml。支持源文件:
- package-lock.json
- yarn.lock
- npm-shrinkwrap.json