为什么考虑用pnpm包管理器?Cloudprg2024/07/28 12:47:27阅读2分钟

首页图

https://qborfy.com/assets/img/pnmp-node-modules-structure.jpg

前言

  • 包管理工具大致原理是怎么样的?
  • 为什么包管理工具要选择pnpm?
  • pnpm与npm yarn有什么不同之处?
  • pnpm的包管理设计上有什么巧妙点?

包管理大致原理

  • 在依赖区间中解析出具体的依赖版本
  • 载对应的压缩包到本地的离线镜像
  • 将依赖从本地的离线镜像解压到本地缓存
  • 将依赖从本地缓存取出,并拷贝至一份到node_modules中 其中拷贝到node_modules,涉及到大量的文件I/O,因为node并不知道这个模块是什么,只能根据模块规则去查询,查询不到就去父级目录下的node_modules下继续查询。

yarn相较于npm,他会有一个项目的依赖树概念,它会维护一张静态映射表,包含了:

  • 当前依赖树包含了哪些依赖的哪些版本
  • 依赖包之间的关联关系
  • 这些依赖包在文件中的具体位置

pnpm相较于其他优点

  • 安装速度快: pnpm的包管理是嵌套结构,相比npm/yarn的扁平结构(扁平结构算法复杂),只更新变化的内容。
  • 节省磁盘空间: pnpm本地存储地址如果已存在安装包,则直接通过hard-link的形式链接到实际地址。

嵌套结构和扁平结构的区别

嵌套结构:

  • 安装重复的依赖包(不同的包,内部都依赖了lodash,则会重复安装)
  • 相同的实例不能共享(比如react有内部变量,两个不同包中的react实例不能共享,否则会引发不可预知的bug)
  • 包依赖嵌套层次过深问题,不利于node模块查询

扁平结构:

  • 扁平算法复杂度高,耗时长
  • 仍然可以非法访问没有声明过依赖的包(子包的幽灵依赖问题)
  • 依赖引用的不确定性 即便转为 扁平结构 ,也不能完全解决问题,尤其是两个模块中依赖了不同版本的同一库时(比如 a@1.0.0 和 a@1.1.0),在扁平化时还要考虑扁平顺序,这也是锁文件诞生的原因
package-lock.json 记录了每一个依赖的具体版本和下载地址,这样就不用去远程仓库查询了。随后直接进入文件完整性校验,即hash校验,减少了大量的网络请求。

既然嵌套结构缺点明显,为啥pnpm依然采用?

因为pnpm已经规避了这一系列问题,还列举了不同版本的模块在pnpm store作对应版本处理。根目录只会有一个依赖,然后软连接到.pnpm下,当然.pnpm下的依赖都hard link到pnpm store中。

pnpm的包管理优势是什么?

  • 局部更新:安装速度快,嵌套结构没有扁平化复杂度高,耗时短,且只变化更新部分
  • 节省磁盘空间:多个子包油相同的依赖,只会安装一次。hard link到pnpm store,对应依赖及版本号,如果校验到则直接硬连接拿来用。

总结

  • pnpm包管理器 节省磁盘空间,类似于diff思想安装依赖
  • 虽然嵌套结构会引发 重复安装依赖,相同实例不能共享,依赖嵌套层次过深问题,但pnpm通过软连接依赖,硬链接到pnpm store的方式解决了这些问题。
  • yarn npm的扁平化管理可能导致依赖引用的不确定性 & 幽灵依赖 & 时间复杂度
标签:
评论(0)
暂无评论
暂无评论
留言板