起步
什么是幽灵依赖?要理解这个概念就要知道它是怎么产生的。
之所以叫依赖就是我们在进行依赖管理时可能产生的,下面我们来演示下这个过程,我们新建两个文件夹分别用npm和pnpm来管理依赖:
首先在npm文件夹中,我们通过npm init
初始化后,尝试安装express。
可以看到,在命令执行完成后,自动生成了node_modules文件夹,但是,我们明明只安装了express一个库,为什么会有这么多其它的目录呢?原因是express可能依赖了其它的库,其它的库可能还依赖了其它的库,就这样npm帮我们把这些库全部下载了下来。我们注意到,node_modules下面有个库叫做accepts
,但是我们的package.json
中只的dependencies
项只有express
一个依赖,我们能引入使用accepts
这个库吗?答案是可以,Node.js 不会关乎你的文件中有什么,你访问到根目录中的所有包:
可以看到我们能正常使用accepts
这个包,但是我们的dependencies
选项并没有声明,那么accepts
这个依赖就可以被叫做幽灵依赖,这样可能会造成什么问题呢?
-
假如说某天我们需要升级
express
依赖的版本,但是升级后的版本不在依赖accepts
这个库了,但是我们的代码中却还在使用这个库,就会导致我们的代码报错 -
或者说随着
express
版本的升级的同时,accepts
这个库也升级了版本,更新了部分api的使用,直接的也就造成了我们的代码报错
接下来我们来看下pnpm是怎么解决幽灵依赖问题的 ,通过pnpm init
,随后安装express
,相较于npm生成的目录是这样的:
可以看到nodeule_modues下面只剩下了express
,那么问题是express
的实现还依赖了其它库,其他库的目录被放到哪了呢?是放到express下了吗?这里可以点开express目录,发现下面并没有node_modules目录,很显然,这些依赖项并没有被放到express目录下。
但是我们可以注意到,在我们的根目录生成了一个.pnpm
的目录,这个目录是做什么的?另外当我们在文件夹中查看时发现,这个express目录是一个软连接,为什么会是一个快捷方式呢?
原因是pnpm对包的管理方式和npm不同,在pnpm官方的角度,我们只安装了 express
,所以它是唯一一个我们应用拥有访问权限的包。 .pnpm
以平铺的形式储存着所有的包,也就是我们express
所依赖的包,express
所有的依赖都软链至了 node_modules/.pnpm/
中的对应目录,所以真正的express
存在.pnpm
中,这个时候我们再去尝试使用accepts
这个包,控制台就会直接提示报错信息,所以也就不存在幽灵依赖的问题了。