pnpm 简介

pnpm 简介

1. 与npm,yarn性能比较

actioncachelockfilenode_modulesnpmpnpmYarnYarn PnP
install33.8s20.1s20.3s40.7s
install2.1s1.4s2.6sn/a
install9.1s5.3s7.8s1.7s
install13.5s9.3s14.1s7.7s
install15s17.2s14.2s33.4s
install2.5s3s8.8sn/a
install2s1.4s8.7sn/a
install2.5s11.2s14.7sn/a
updaten/an/an/a8.9s12s6.9s14.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。支持源文件:

  1. package-lock.json
  2. yarn.lock
  3. npm-shrinkwrap.json