A diagram to show how pnpm works

This post was created without the involvement of AI.

Pnpm may be alternative of npm、yarn and lerna. But do you know how pnpm works?

pnpm-change.png

该图已被 pnpm 官网收录

幽灵依赖问题#

仓库依赖的 NPM 包,及其依赖包的依赖,平铺在 **.pnpm **这个隐藏的磁盘目录。只有仓库依赖的包会被列在当前仓库的 node_modules 下,其他包则无法被 resolve 到。

比如仓库依赖 bar@1.0.0,bar 包依赖 foo@1.0.0。这两个包会平铺在 .pnpm,当前仓库的 node_modules 只列出项目依赖的包的符号链接(注意箭头方向)。

依赖地狱问题#

依赖会平铺在 .pnpm 目录。

Doppelgagers 问题#

从上图可以看清楚,.pnpm 目录下依赖 bar 的结构是:

$ tree -L 2
.
└── node_modules
    ├── foo -> ../../foo@1.0.0/node_modules/foo
    └── bar

也就是 NPM 包 bar 的依赖都在自身 node_modules 下可以 reslove 到。依赖的各影分身都只会下载一份(更快),也不会被错误 reslove。


以下是更新内容:如果是首次使用 pnpm 的话,也许会发现实际的结构和上图有些出入,我觉得这些出入可以统称为「面向社区生态的妥协」。而其中主要的,和这四个参数有关。​

面向社区生态的妥协#

如果这个配置开启,你会发现 .pnpm 目录下有一个 node_modules 目录,这个目录下的包全部软链到 .pnpm 下的包。

$ cd node_modules/.pnpm && tree -L 3

.pnpm
    ├── bar@1.0.0
    ├── lodash@2.0.0
    └── node_modules
        ├── lodash@2.0.0 -> ../lodash@2.0.0/node_modules/lodash
        └── bar@1.0.0

这是因为 pnpm 默认情况下,这个 hoist 配置是开启的,称之为“半严格” 的设计:项目无法 reslove 自己没有依赖的包,但是项目的依赖可以 reslove 到其未被依赖的包。

比如项目的直接依赖 bar 其实并没有依赖 lodash@2.0.0 这个包,但是仍然可以被 reslove 到,就是因为 .pnpm 下这个 node_modules 目录类似 NPM V3 平铺了所有依赖包,根据 Node 的查找算法,是可以找到这个依赖的。这就是 pnpm 的妥协策略之一

这个配置就比较好理解了。hoist-pattern 配置为 *,就是和 hoist 为 true 表达的含义一样。

当你的项目依赖了 eslint 或 babel,使用 pnpm 安装,在项目的 node_modules 下,你会发现它们的影子。

tree node_modules -L 1

node_modules
  ├── @babel
  ├── @eslint
  ├── @types
  ├── @typescript-eslint
  ├── eslint
  ├── eslint-config-ali
  ├── eslint-import-resolver-node
  ├── eslint-module-utils
  ├── eslint-plugin-import
  ├── eslint-plugin-jsx-plus

这时候,有可能就怀疑自己了。正常来说,只依赖了 eslint,不应该包含 eslint 的其他 plugin,因为我并没有直接依赖它们。但事实上,eslint 在依赖的问题上本身就 存在 bug 的。而 pnpm 默认将其 hoist 至项目的根 node_modules 下(public-hoist-pattern 的默认配置是 ['types', 'eslint', '@prettier/plugin-*', 'prettier-plugin-'])。这是 pnpm 的第二个妥协策略

第三个妥协策略就是 shamefully-hoist,设置为 true 时,就把依赖的依赖,以及依赖都提升至项目根目录 node_modules 下,类似 NPM V3 的结构。

portrait

Have a weekly visit of

Howl's Moving Castle

Get emails from me about web development, tech, and early access to new articles. I will only send emails when new content is posted.

Subscribe Now!