首页图
前言
- 包管理工具大致原理是怎么样的?
- 为什么包管理工具要选择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的扁平化管理可能导致依赖引用的不确定性 & 幽灵依赖 & 时间复杂度