pnpm 是如何有效避免幻影依赖的

833 阅读3分钟

npm 作为最广泛使用的包管理工具之一,虽然功能强大,但在实际使用中,开发者可能会遇到一种令人头疼的问题——幻影依赖

npm幻影依赖

在项目中安装了库A,但是库A又依赖库B,所以你的项目中其实可以直接使用库B,即使你并没有直接安装库B,这就是幻影依赖,也叫幽灵依赖。最常见的场景就是:你的项目自己开发的很好,别人一拉代码,安装依赖运行不起来...

造成的问题:

  •  版本问题

image-20240816161236127.png

在项目中安装了A,A依赖着B,并且我们导入了B并使用,之后升级了A的版本,B的版本如果也跟着升级,这时之前使用的B可能就有问题
  •  依赖丢失问题

image-20240816161516478.png

如果A是开发环境依赖,那么生产环境是不会打包的(A和B),开发时我们使用了B,但是生产环境没有,导致依赖丢失

依赖图

image-20240816162033659.png

早期的npm文件树:库A和库B都依赖库D,那就在A和库B的文件夹下都存放库D,这种放方式导致依赖体积庞大

npm的处理方式

image-20240816162233454.png

将所有的包打平(flat,扁平结构),全部作为同一级存放在node_modules下(借鉴yarn),看看pnpm的解决方式

pnpm软链接

软链接是一个特殊类型的文件,它包含了另一个文件的路径。

pnpm是创建一个仓库,将直接依赖和间接依赖全部放进去,当我们使用时不会直接在这里寻找

pnpm在建立node_modules文件树时,会采用npm最早的那种做法(下图左)

image-20240816162509667.png

巧妙的是:这里的树里面的文件夹都不占用磁盘空间,通过软链接的方式找到仓库里面的依赖包来使用

  • node_modules文件夹下只有我们手动安装的依赖,
  • .pnpm下保存了手动安装的依赖和所有的幻影依赖,以平铺的形式存放。

image-20240312162057128.png

对于那些需要构建的包,它使用软连接(符号链接,Symbolic Link)连接到存储在项目中的实际位置。这种方式使得包的安装非常快速,并且节约磁盘空间。

image.png

文件夹后有个回车的icon,这个代表当前这个文件是一个软链接文件。

软链接的设计既保证了不会出现幽灵依赖的问题,同时也能兼容 node 的寻找模块方式。

羞耻的提升:原则上幻影依赖不可以使用,但是可以添加配置使node_modules下的依赖扁平化,提升到 node_modules中

.npmrc

shamefully-hoist = true

pnpm硬链接(Hard Link)

硬链接是文件系统中的一个链接,它指向磁盘上的数据。

  •  pnpm 有个根目录来存储下载的包,一般都是保存在 user/.pnpm-store 下
  •  pnpm 通过硬链接的方式保证了相同的包不会被重复下载:比如说项目A安装了express@4.17.1,之后项目B中也安装express@4.17.1的时候是会被复用的,这两个项目中express文件指向的是同一个inode,新项目复用就会增加这个文件的硬链接个数

image-20240816162848121.png

软链硬链在 pnpm 中起着至关重要的作用。通过使用软链和硬链技术,pnpm 不仅避免了幽灵依赖的问题,还提高了包的复用率,节省了磁盘空间。这些特性使得 pnpm 在前端开发中成为了一个强大而高效的包管理工具。