Q: 为什么要迁移pnpm?
相比于npm,pnpm有一些优势:
-
更快的安装速度: 在安装包时,pnpm使用了硬链接的方式,将已安装的包链接到新的目录下,而不是复制或下载包。这样,当你安装一个包的不同版本或者不同项目使用同一个包时,它们会共享已经安装的包,减少了磁盘空间的占用,同时也加速了安装的速度。
-
更少的磁盘空间占用: 由于pnpm使用硬链接的方式共享已安装的包,因此相比于npm,pnpm占用更少的磁盘空间。
-
更好的本地缓存: pnpm会缓存包的元数据和二进制文件到本地缓存中,这样再次安装相同的包时,会从本地缓存中读取,而不是重新下载。这样可以提高安装包的速度,并减少网络带宽的消耗。
-
更好的多项目管理: pnpm可以管理多个项目的依赖,可以将相同的依赖安装在一个公共的位置,减少磁盘空间的占用,并且可以快速地切换项目之间的依赖关系。
-
更好的可重复性: pnpm使用了锁文件来保证安装包的版本一致性,同时也支持自定义的锁文件名称和路径。这样可以确保项目在不同的环境中的安装结果一致,增强了可重复性。
需要注意的是,pnpm相比于npm也存在一些缺点,例如兼容性问题、社区支持不如npm等。因此,在选择使用pnpm还是npm时,需要根据自己的实际需求和项目情况进行权衡。
Q: 上面提到的硬链接和符号链接是什么?
硬链接和符号链接都是文件系统中的链接方式,它们的作用是可以将一个文件或目录链接到另一个文件或目录上,从而实现共享或复制等功能。下面我来简单介绍一下它们的区别和示例。
硬链接
硬链接是指在文件系统中,将一个文件名链接到另一个文件上,使它们指向同一个物理数据块,也就是说,这两个文件名共享同一个inode节点。硬链接的本质是将一个文件名指向一个已存在的文件。
硬链接的特点:
- 硬链接不能跨越不同的文件系统,因为inode节点只存在于一个文件系统中。
- 硬链接可以看作是原文件的一个副本,它们的文件权限、拥有者、修改时间等都是相同的。
- 删除硬链接并不会删除原文件,只有当所有的硬链接都被删除后,原文件才会被真正删除。
下面是一个硬链接的示例:
$ touch file1 # 创建一个文件
$ ln file1 file2 # 创建硬链接
$ ls -li file* # 查看文件inode节点
12345 -rw-r--r-- 2 user user 0 Apr 26 10:00 file1
12345 -rw-r--r-- 2 user user 0 Apr 26 10:00 file2
可以看到,file1和file2的inode节点是相同的,说明它们共享同一个物理数据块。
符号链接
也称之为软链接,符号链接是指在文件系统中,创建一个特殊的文件,其中包含了另一个文件的路径,通过这个特殊文件来链接到目标文件。符号链接的本质是将一个文件名指向一个路径。
符号链接的特点:
- 符号链接可以跨越不同的文件系统,因为它们只是一个指向文件或目录的路径。
- 符号链接指向的是目标文件或目录的路径,而不是inode节点,因此,目标文件或目录的属性信息可以独立于符号链接存在。
- 删除符号链接不会影响目标文件或目录,也不会删除它们。
下面是一个符号链接的示例:
$ touch file1 # 创建一个文件
$ ln -s file1 file2 # 创建符号链接
$ ls -li file* # 查看文件inode节点
12345 -rw-r--r-- 1 user user 0 Apr 26 10:00 file1
67890 lrwxr-xr-x 1 user user 5 Apr 26 10:01 file2 -> file1
可以看到,file2是一个符号链接文件,它的inode节点和file1不同,而是一个指向file1的路径。
Q: 看到一些文章里说pnpm走的是硬链接,有的说用了软连接。到底走的是什么?
其实,pnpm是软连接和硬链接都用了。可以这么理解,pnpm在机器上某个地方存放安装好的所有依赖包,这些依赖包是独立于我们代码仓库的,这也是前面说的pnpm在安装速度和磁盘空间占用上的优点。而我们的代码库确实是先通过硬链接的方式来建立代码库和已安装过的依赖包之间的共享关系。可以打开代码库看到node_modules
下有一个.pnpm文件夹,里面放的就是当前代码库建立的硬链接。
.pnpm
下的文件都是一些名字很长的,长这样:
这里不用关心具体是什么,我们需要关心的是node_mpdules
下我们认识的npm
依赖包,它们正是通过软连接的方式来链接到.pnpm
下的这些依赖包的。在vscode下,可以明显看到npm
包后面的软连接标识:
如果想看一下这些软连接到底指向哪里的,可以:
# 进入node_modules目录
cd node_modules
# 枚举文件列表
ll
可以看到,这就是node_modules
下软链接到.pnpm
下的。
Q: 这个模式跟npm dedupe是不是很相似,有什么不同?
pnpm的硬链接模式和npm的dedupe功能是类似的,都是通过共享已安装的包来减少磁盘空间的占用,同时也可以提高安装包的速度。但它们之间还是存在一些不同:
-
原理不同: pnpm使用硬链接的方式共享已安装的包,而npm使用的是符号链接的方式共享已安装的包。硬链接是文件系统的一种特殊链接,它可以将一个文件链接到另一个文件上,使它们共享相同的内容。符号链接则是一个指向另一个文件或目录的特殊文件。
-
适用范围不同: pnpm的硬链接模式可以在多个项目之间共享已安装的包,而npm的dedupe功能只能在单个项目内共享已安装的包。
-
优势不同: pnpm的硬链接模式可以减少磁盘空间的占用和提高安装包的速度,而npm的dedupe功能只能减少磁盘空间的占用。
-
实现方式不同: pnpm使用了自己的包管理器和包存储库,而npm使用了公共的包管理器和包存储库。这也是导致它们之间存在差异的一个重要原因。
需要注意的是,无论是使用pnpm的硬链接模式还是npm的dedupe功能,都需要谨慎使用,以避免出现意外的错误。特别是在使用硬链接模式时,如果多个项目共享同一个包,需要注意不要在一个项目中修改了该包的文件,导致其他项目也受到影响。
Q: pnpm对于node版本有要求吗?
pnpm有对node版本的要求。官方文档中列出的最低支持版本是Node.js 10.x,推荐使用的版本是Node.js 14.x。如果使用的是较旧的Node.js版本,可能会导致安装和使用pnpm时出现错误。
我这里本来用的是Node14.x。因为其他原因,本次也给Node升级到16.x了。
Q: pnpm有类似npm ci的命令吗?
补充:
npm ci
主要是用于刚刚在download了一个仓库后,还没有node_modules的时候让npm完全根据package.json和package-lock.json的规范来install依赖包。相比较于直接走npm i
,npm ci
会带来更精确的小版本版本号控制,因为npm i对于一些"^1.0.2"这样的版本号,可能会按照1.x.x这样的规范给你无感升级了,造成和之前某些包版本号之间的差异。
但是当本地已有node_modules的时候,就没办法用npm ci
命令了。
是的,pnpm也有类似 npm ci
命令的功能,可以使用 pnpm install --frozen-lockfile
命令实现。它会根据 package-lock.json
或 pnpm-lock.yaml
确定依赖关系,并且在安装期间不会更新任何包。此命令类似于 npm ci
和 yarn install --frozen-lockfile
命令。
Q: pnpm@7搭配husky@8后commit一直失败怎么办?
这是因为hooks出问题了。某些代码库里会在commit时候会添加一些hook用来处理commit相关的事务,比如生成commit-id之类的。
husky@8后需要处理一下这个:
husky add .husky/commit-msg 'sh .git/hooks/commit-msg "$@"'
手动把之前.git/hooks下的脚本拷贝到.husky下。
友情提示:.git和.husky一般都是在项目根目录下的隐藏文件夹喲~