关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

昨晚,我体会了没有 pnpm 的痛(二)

发布时间:2023-06-26 20:00:06

pnpm 是怎么做到的


这就要涉及文件系统中两个概念:硬链接、软链接;


硬链接


在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index),在 Linux 中,允许多个文件名指向同一索引节点,一般这种连接就是硬链接。

硬链接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的链接。只删除一个链接并不影响索引节点本身和其它的链接,只有当最后一个链接被删除后,文件的数据块及目录的链接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬链接文件均被删除。

语法:ln filename [linkname ]

  1. 硬链接的新建是为同一inode号添加文件名 (本质是在目录条目里为inode号增添一个文件名映射,指向同一个inode表数据,因此数据相同)
  2. 新建硬链接,链接数增加(链接数实质就是 inode号 对应文件名的个数;当 inode 号映射的文件名不存在时,此 inode号就会被系统回收重用)
  3. 硬链接文件和原文件之间数据共享,但又互相独立;(修改其中任意一个文件的数据,其他的文件数据都会改变,删除硬链接文件则对应的链接数会减少,如果是最后一个链接数则直接删除文件。)
  4. 不能跨分区和跨设备创建硬链接
  5. 不能对目录创建硬链接 (目录最多有三个硬链接,目录本身,目录下的 . ,子目录下的 …)

示例: 以下命令建议在 Linux 虚拟机中或 MacOS 中操作:


因涉及一些执行语句,禁止写入,请联系客服获取


软链接


有点像是 window 中的快捷方式,它本身也是一个文件,只不过保存的是它指向的文件的全路径,访问时将通过它访问所指向的文件路径以打开指定文件,所以当删除源文件时,打开它将报错指示无相关路径。

语法:ln -s filename [linkname ]

  1. 软链接实质是新建一个文件快捷方式,存放的数据是原文件的文件名,文件数据大小是原文件名字的字节数;访问时通过文件名指向到原文件数据
  2. 软链接支持跨分区
  3. 可以创建目录软链接
  4. 软链接文件依赖于原始文件 ;删除原始文件,软链接文件会失效示例: 在 poetryFile 的基础上我们新建一个软链接


因涉及一些执行语句,禁止写入,请联系客服获取


在文件当前所在目录通过 ls -hl 查看信息,可以发现硬链接文件和源文件各种信息均一致,可以说是一样的文件,而软链接文件则只是存储了指向信息,所以可以看到明显的差别。


因涉及一些执行语句,禁止写入,请联系客服获取


pnpm对硬链接,软链接的运用


当使用 npm 或 Yarn 时,如果你有100个项目使用了某个依赖(dependency),就会有100份该依赖的副本保存在硬盘上。而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中,所以: 如果你用到了某依赖项的不同版本,那么只会将有差异的文件添加到仓库。 例如,如果某个包有100个文件,而它的新版本只改变了其中1个文件。那么 pnpm update 时只会向存储中心额外添加1个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。 所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会 硬链接 到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。因此,您在磁盘上节省了大量空间,这与项目和依赖项的数量成正比,并且安装速度要快得多! 摘自: pnpm.io/zh/motivati…官方介绍示意图:



在pnpm 出现之前,npm 和 yarn 为了提升装包效率以及复用率,采用了扁平化对策略,也就是所有的依赖包都装到根目录下,这样会导致node_modules 下的包和 package.json 中定义的存在很大出入,这会引起幽灵依赖( 幽灵依赖” 指的是项目中使用了一些没有被定义在其package.json 文件中的包。)


如图:



虽然我只需要express 这一个包,但是experss 所依赖的包都被平铺到了根目录,这将导致我可以直接使用这些没在 package.json 中定义的包,虽然项目可以运行,但是将是个潜在的隐患。而如果使用 pnpm, 它将使用软链接来解决这个问题:



可以看到,node_modules 下结构和我们期望的几乎一样了,很简洁,之前的那些包被放到了 .pnpm 里,其实这里的 express 就是个软链接,执行 ls -hl 查看其详细信息, 可以看到它指向了 .pnpm 下的express 文件,所以说 pnpm 的软链接就是将 node_modules 里的文件软链接到对应的 .pnpm/[package_name]@version/node_modules/[package_name] 中。


因涉及一些执行语句,禁止写入,请联系客服获取


而 .pnpm 中的文件则是一个对源文件的硬链接,我来验证下,首先找到 pnpm-test 项目下找到 express 的文件路径,通过终端指令 stat -s index.js读取其详细信息,发现其 index.js inode节点为 st_ino=5206568 并且有8个相同的硬链接,然后建一个新项目,并安装express,发现 其节点inode 仍然是st_ino=5206568,但是硬链接数量增加到了 9 个,可以看出express 下的index.js 实际上是被复用的。



那么,pnpm 下载的源文件到底在哪里呢,以 macOS 为例,会默认安装到当前用户的根目录下,是一个隐藏文件,你也可以通过修改配置来更换其位置 因涉及一些执行语句,禁止写入,请联系客服获取



总结


pnpm == p(performant) + npm,代表高性能的 npm,我觉得目前可用性已经很好了,虽然可能迁移中会遇到一些问题比如幽灵依赖,但是还是值得升级的。特别是新项目,无脑用起来吧。


/template/Home/leiyu/PC/Static