什么是幽灵依赖?pnpm是如何解决的?

290 阅读3分钟

起步

什么是幽灵依赖?要理解这个概念就要知道它是怎么产生的。 之所以叫依赖就是我们在进行依赖管理时可能产生的,下面我们来演示下这个过程,我们新建两个文件夹分别用npm和pnpm来管理依赖: 首先在npm文件夹中,我们通过npm init初始化后,尝试安装express。

1.jpg

可以看到,在命令执行完成后,自动生成了node_modules文件夹,但是,我们明明只安装了express一个库,为什么会有这么多其它的目录呢?原因是express可能依赖了其它的库,其它的库可能还依赖了其它的库,就这样npm帮我们把这些库全部下载了下来。我们注意到,node_modules下面有个库叫做accepts,但是我们的package.json中只的dependencies项只有express一个依赖,我们能引入使用accepts这个库吗?答案是可以,Node.js 不会关乎你的文件中有什么,你访问到根目录中的所有包:

2.jpg

可以看到我们能正常使用accepts这个包,但是我们的dependencies选项并没有声明,那么accepts这个依赖就可以被叫做幽灵依赖,这样可能会造成什么问题呢?

  • 假如说某天我们需要升级express依赖的版本,但是升级后的版本不在依赖accepts这个库了,但是我们的代码中却还在使用这个库,就会导致我们的代码报错

  • 或者说随着express版本的升级的同时,accepts这个库也升级了版本,更新了部分api的使用,直接的也就造成了我们的代码报错


接下来我们来看下pnpm是怎么解决幽灵依赖问题的 ,通过pnpm init,随后安装express,相较于npm生成的目录是这样的:

3.jpg

可以看到nodeule_modues下面只剩下了express,那么问题是express的实现还依赖了其它库,其他库的目录被放到哪了呢?是放到express下了吗?这里可以点开express目录,发现下面并没有node_modules目录,很显然,这些依赖项并没有被放到express目录下。

但是我们可以注意到,在我们的根目录生成了一个.pnpm的目录,这个目录是做什么的?另外当我们在文件夹中查看时发现,这个express目录是一个软连接,为什么会是一个快捷方式呢?

4.jpg

原因是pnpm对包的管理方式和npm不同,在pnpm官方的角度,我们只安装了 express,所以它是唯一一个我们应用拥有访问权限的包。 .pnpm 以平铺的形式储存着所有的包,也就是我们express所依赖的包,express 所有的依赖都软链至了 node_modules/.pnpm/ 中的对应目录,所以真正的express存在.pnpm中,这个时候我们再去尝试使用accepts这个包,控制台就会直接提示报错信息,所以也就不存在幽灵依赖的问题了。

5.jpg