pnpm 常见问题
为什么使用硬链接? 为什么不直接创建到全局存储的软链接?
这个问题非常复杂,说来话长,我一点点分析,我花了很多功夫在这个问题上,目前也没有答案,和大家分享一下我的调研结果。
首先,pnpm 官网如此解释
直接软链至全局存储与 Node 的 --preserve-symlinks 标志一起使用是可行的,但是,该方法附带了个自己的问题,因此我们决定使用硬链接。
大意就是可以做,但我们不想,因为会引发新的问题。
require 直接引入软链接
软链接的文件中,使用require 直接引用的包会报错,软链接会从文件原始位置开始查找依赖。
我们希望的是软链可以将其他地方的目录增加到依赖查找路径中。
有兴趣可以去看github 关于软链接引用报错的讨论,这时已经有人提出使用硬链接github.com/nodejs/node…
我们实验一下
如下图,建立两个文件夹a,b
a/index.js中写入,b中安装qs库
const test = require('qs') console.log(test)
b 中建立index.js的软链接index-s.js
执行node index-s.js 发现找不到模块
因为软链接中的require软链接会从文件原始位置开始查找依赖,a中没有node_modules,直接报错了,但是如果是硬链接则不存在这样的问题
--preserve-symlinks
最后node官方,增加了--preserve-symlinks
来专门处理软链接的引用路径问题。
Node.js 有这样一个选项:–preserve-symlinks
,可以设置成按照软链所在的位置查找依赖。
新的问题
–preserve-symlinks 会引发新的问题,但是我查阅了github 的issues,有好几百条的讨论,没有看到有详细解释清楚这个问题的,我现在大概的理解就是node官方对软链接支持的不够好,即使提出了–preserve-symlinks,也有问题,所以pnpm团队不用了。
有兴趣可以看看老外们的讨论
后来,我在node.js 中文文档里找到着这么一句,但是自己没有验证
使用 --preserve-symlinks
会有其他方面的影响。 比如,如果符号连接的原生模块在依赖树里来自超过一个位置,它们会加载失败。 (Node.js 会将它们视为两个独立的模块,且会试图多次加载模块,造成抛出异常。)
最终作者抛弃了这个方案
总结
最后我们再翻译翻译,pnpm 官网的这些话
节省磁盘空间
pnpm通过hard link(硬连接) 机制,把包都存储在全局的pnpm/store/目录下。当安装软件包时,其包含的所有文件都会硬链接自此位置,而不会占用额外的硬盘空间。pnpm 对于同一个包不同的版本也仅存储其增量改动的部分。
快速
安装包之前,如果已经在全局安装过,就不会被再次下载了,节省了安装时间。随着项目增多,效果会越来越明显。
支持单体仓库
pnpm 提供工作空间workspace能力,就是保证一个仓库内多个项目的package.json有自己生效的范围。这个yarn npm 也支持,不算pnpm的突出点。我对monorepos 也没有研究过,这块等后续有时间了,可以对比三个工具的workspace专题讨论。
严格
pnpm 默认创建了一个非扁平化的 node_modules,因此代码无法访问未声明的包,解决了npm 存在的幽灵依赖问题。
待研究的问题
- pnpm-lock.yaml 文件里的属性和生成过程
- pnpm 对peerDependencies 的处理
- 老项目使用yarn 或者npm 如何迁移
- pnpm npm yarn 工作空间workspace的研究
- Java的meavns是怎么管理依赖包的,和前端有什么区别
参考链接
pnpm官网 pnpm.io/zh/
软链、硬链对 Node.js 包寻找的影响 meixg.cn/2021/01/25/…
前端包管理工具 npm yarn cnpm npx juejin.cn/post/710244…
pnpm 有什么优势 q.shanyue.tech/engineering…