Skip to content
☆´∀`☆
On this page

pnpm & npm

来源image.png

pnpm 是一个包管理器

  • 包安装速度快
  • 磁盘空间利用高效
    • 不会重复安装同一个包,如果 100 个项目都依赖 lodash,那么 lodash 很可能就被安装了 100 次,磁盘中就有 100 个地方写入了这部分代码。但在使用 pnpm 只会安装一次,磁盘中只有一个地方写入,后面再次使用都会直接使用 hardlink。(硬链接)
    • 即使一个包的不同版本,pnpm 也会极大程度地复用之前版本的代码。比如 lodash 有 100 个文件,更新版本之后多了一个文件,那么磁盘当中并不会重新写入 101 个文件,而是保留原来的 100 个文件的 hardlink,仅仅写入那一个新增的文件。
  • 支持monorepo (用一个 git 仓库管理多个子项目)(开源 mon 管理工具Leran
    • 所有的子项目都存放在根目录的 packages 目录下,那么一个子项目就代表一个 package。(目录结构参考Babel)(还有 element-plus)
    • 在根目录下 pnpm add A -r, 那么所有的 package 中都会被添加 A 这个依赖。

npm/yarn i 的原理

执行命令后,会构建一个依赖树,然后针对每个节点下的包,经历以下步骤:

  1. 将依赖包的版本区间解析为具体版本
  2. 下载对应版本依赖的 tar 包(这应该是个压缩包)到本地离线镜像
  3. 将依赖从离线镜像解压到本地缓存
  4. 将依赖从缓存拷贝到当前目录的 node_modules 目录

在 npm1,npm2 中,呈现的是嵌套结构,即当依赖 A 中有依赖 B,则依赖 B 就会嵌套在依赖 A 中。会出现以下情况:

  • 依赖层次太深,文件路劲贼长
  • 大量的包会被重复安装,体积超超超大
  • 模块实例不能共存。即 A,B 都有依赖包 C,则 A、B 中 C 的内部变量不能共享。实例不是同一个~

所以,npm3 开始,采用了扁平化依赖。你会发现,装一个依赖,node_m 目录下会出现好多文件夹~ 在安装新包的时候,会不停地在 node_m 中查找,如果找到相同版本的包就不会重复安装。(node_require 机制) 但是,它存在以下问题:

  • 依赖结构的不确定性
  • 扁平化算法的复杂性高,耗时长
  • 项目中仍可以非法访问没有声明过依赖的包

假如现在项目依赖两个包 foo 和 bar,这两个包的依赖又是这样的:

那么它会出现两种情况: image.pngimage.png 取决于 foo 和 bar 在 package.json 中的位置,如果 foo 声明在前面,那么就是前面的结构,否则是后面的结构。 这也是lock文件诞生的原因,为了确保 install 之后产生确定的 node_m 目录。

pnpm 的原理

  • 用软链接梳理了包结构

  • 硬连接就是同一个文件的不同引用,而软链接是新建一个文件,文件内容指向另一个路径。

  • 全局仓库保存一份 npm 包的内容,其余的地方都 link 过去

原理图