NPM包管理工具的幻影依赖问题

随着前端工程化的不断完善,各种包管理工具和构建工具也越来越多。在Node生态里,绕不开NPM,Yarn,PNPM这些包管理工具,但是项目中一般都是用PNPM包管理工具而不用NPM,有一部分原因就是因为NPM包管理工具容易产生幻影依赖的问题。

随着前端工程化的不断完善,各种包管理工具和构建工具也越来越多。在Node生态里,绕不开NPM,Yarn,PNPM这些包管理工具,但是项目中一般都是用PNPM包管理工具而不用NPM,有一部分原因就是因为NPM包管理工具容易产生幻影依赖的问题。

幻影依赖

假设我们使用 npm install 命令给我们的项目安装 element-plus 依赖,安装后在 node_modules 文件夹下查看依赖文件,会发现有很多文件夹,有很多依赖都被下载下来了,这是因为 element-plus 等项目的直接依赖有很多间接依赖,也就是我们的项目依赖A,而A又依赖B,B又依赖C, A→B→C,所有的这些依赖都被安装到了node_modules 里。

而这里的依赖B,或者依赖C虽然我们没有在packages.json里,但是却可以在代码里直接引入使用,直接 import xxx 就行。

也就是说,在我们代码里面可以直接使用一个在依赖申明文件 packages.json 中并不存在的依赖,这就是幻影依赖。

幻影依赖产生的问题

幻影依赖至少会产生2个问题:

假设目前代码是这种情况:申明了A依赖,A→B,因为A依赖了B,所以在代码里直接使用了B。

  1. 依赖的版本问题: 这时如果A刚好有新版本升级了,A升级会自动升级A所依赖的B,这时代码里直接使用的B依赖就很有可能报错。如果在生产环境里遇到这个问题,一般是很难排查的。
  2. 依赖丢失问题: 这时,如果我们的A依赖是开发环境dev的依赖,放到生产环境的话是不存在A依赖的,此时代码在本地开发环境可以正常运行,而在生产环境,就会报错了。

NPM包管理工具的问题

NPM包管理工具也有在解决这个幻影依赖的问题,只是没有很好的解决。

问题产生的根源:依赖图和文件树是不同的。一个是图结构,一个是树结构。

树是一种“层次结构”,图是一种“网络”关系。

假设项目中的真实依赖是上图中左边的依赖图,项目直接依赖了A,A间接依赖了B、C、D

NPM之前的解决方案是上图中右边的文件树,A依赖了B,B和C共同依赖了D,所以B依赖的文件夹里有一份D的源码,C依赖的文件夹里也有一份D的源码,这么做就造成了磁盘空间的浪费,导致依赖的体积进一步变大。

NPM后来借鉴了Yarn包管理工具的做法,不管间接依赖了多少包,统一都放到根目录 node_modules下,如下图:

这么做也还是无法避免幻影依赖的问题,只是解决了一部分磁盘占用空间大的问题。

PNPM包管理工具的解决方案

在PNPM中,所有的依赖包括间接依赖存储在类似一个容器的 store 中,就是 node_modules 文件夹中的 .pnpm 文件夹里,与 yarn 的存储类似,同时又使用类似快捷方式的做法(硬链接和软连接都有使用)在 node_modules 中构造了一个文件结构,如上图中虚线部分图示。而这个快捷方式因为只是链接到了store中的正式存储内容,所以并不占空间,又能很好的保留依赖的关系。并且在代码中引用只能引用到A,因为 B、C、D 都不在node_modules里,而是 .pnpm 里。

所以在实际开发中,更推荐用PNPM做包管理工具,不仅下载快,占用磁盘空间小,还能避免幻影依赖的问题。

策略模式优化多重判断
CSS多行溢出,兼容性比较好的做法

评论区

评论加载中...