[{"data":1,"prerenderedAt":133},["ShallowReactive",2],{"\u002Fposts\u002F8a960ce":3,"surround-\u002Fposts\u002F8a960ce":122},{"id":4,"title":5,"body":6,"categories":99,"date":101,"description":12,"draft":102,"extension":103,"image":104,"meta":105,"navigation":107,"path":108,"permalink":108,"published":104,"readingTime":109,"recommend":114,"references":104,"seo":115,"sitemap":116,"stem":117,"tags":118,"type":120,"updated":101,"__hash__":121},"content\u002Fposts\u002F2024\u002FNPM包管理工具的幻影依赖问题.md","NPM包管理工具的幻影依赖问题",{"type":7,"value":8,"toc":90},"minimark",[9,13,17,20,23,26,29,32,35,45,49,52,55,58,62,65,68,71,74,77,81,84,87],[10,11,12],"p",{},"随着前端工程化的不断完善，各种包管理工具和构建工具也越来越多。在Node生态里，绕不开NPM，Yarn，PNPM这些包管理工具，但是项目中一般都是用PNPM包管理工具而不用NPM，有一部分原因就是因为NPM包管理工具容易产生幻影依赖的问题。",[14,15,16],"h2",{"id":16},"幻影依赖",[10,18,19],{},"假设我们使用 npm install 命令给我们的项目安装 element-plus 依赖，安装后在 node_modules 文件夹下查看依赖文件，会发现有很多文件夹，有很多依赖都被下载下来了，这是因为 element-plus 等项目的直接依赖有很多间接依赖，也就是我们的项目依赖A，而A又依赖B，B又依赖C， A→B→C，所有的这些依赖都被安装到了node_modules 里。",[10,21,22],{},"而这里的依赖B，或者依赖C虽然我们没有在packages.json里，但是却可以在代码里直接引入使用，直接 import xxx 就行。",[10,24,25],{},"也就是说，在我们代码里面可以直接使用一个在依赖申明文件 packages.json 中并不存在的依赖，这就是幻影依赖。",[14,27,28],{"id":28},"幻影依赖产生的问题",[10,30,31],{},"幻影依赖至少会产生2个问题：",[10,33,34],{},"假设目前代码是这种情况：申明了A依赖，A→B，因为A依赖了B，所以在代码里直接使用了B。",[36,37,38,42],"ol",{},[39,40,41],"li",{},"依赖的版本问题： 这时如果A刚好有新版本升级了，A升级会自动升级A所依赖的B，这时代码里直接使用的B依赖就很有可能报错。如果在生产环境里遇到这个问题，一般是很难排查的。",[39,43,44],{},"依赖丢失问题： 这时，如果我们的A依赖是开发环境dev的依赖，放到生产环境的话是不存在A依赖的，此时代码在本地开发环境可以正常运行，而在生产环境，就会报错了。",[14,46,48],{"id":47},"npm包管理工具的问题","NPM包管理工具的问题",[10,50,51],{},"NPM包管理工具也有在解决这个幻影依赖的问题，只是没有很好的解决。",[10,53,54],{},"问题产生的根源：依赖图和文件树是不同的。一个是图结构，一个是树结构。",[10,56,57],{},"树是一种“层次结构”，图是一种“网络”关系。",[59,60],"pic",{"src":61},"https:\u002F\u002Ffile.dhbxs.top\u002Fblog_img\u002F1776233103384_image.webp",[10,63,64],{},"假设项目中的真实依赖是上图中左边的依赖图，项目直接依赖了A，A间接依赖了B、C、D",[10,66,67],{},"NPM之前的解决方案是上图中右边的文件树，A依赖了B，B和C共同依赖了D，所以B依赖的文件夹里有一份D的源码，C依赖的文件夹里也有一份D的源码，这么做就造成了磁盘空间的浪费，导致依赖的体积进一步变大。",[10,69,70],{},"NPM后来借鉴了Yarn包管理工具的做法，不管间接依赖了多少包，统一都放到根目录 node_modules下，如下图：",[59,72],{"src":73},"https:\u002F\u002Ffile.dhbxs.top\u002Fblog_img\u002F1776233120180_image.webp",[10,75,76],{},"这么做也还是无法避免幻影依赖的问题，只是解决了一部分磁盘占用空间大的问题。",[14,78,80],{"id":79},"pnpm包管理工具的解决方案","PNPM包管理工具的解决方案",[59,82],{"src":83},"https:\u002F\u002Ffile.dhbxs.top\u002Fblog_img\u002F1776233128901_image.webp",[10,85,86],{},"在PNPM中，所有的依赖包括间接依赖存储在类似一个容器的 store 中，就是 node_modules 文件夹中的 .pnpm 文件夹里，与 yarn 的存储类似，同时又使用类似快捷方式的做法(硬链接和软连接都有使用)在 node_modules 中构造了一个文件结构，如上图中虚线部分图示。而这个快捷方式因为只是链接到了store中的正式存储内容，所以并不占空间，又能很好的保留依赖的关系。并且在代码中引用只能引用到A，因为 B、C、D 都不在node_modules里，而是 .pnpm 里。",[10,88,89],{},"所以在实际开发中，更推荐用PNPM做包管理工具，不仅下载快，占用磁盘空间小，还能避免幻影依赖的问题。",{"title":91,"searchDepth":92,"depth":92,"links":93},"",4,[94,96,97,98],{"id":16,"depth":95,"text":16},2,{"id":28,"depth":95,"text":28},{"id":47,"depth":95,"text":48},{"id":79,"depth":95,"text":80},[100],"技术","2024-08-27 05:56:13",false,"md",null,{"slots":106},{},true,"\u002Fposts\u002F8a960ce",{"text":110,"minutes":111,"time":112,"words":113},"5 min read",4.99,299400,998,0,{"title":5,"description":12},{"loc":108},"posts\u002F2024\u002FNPM包管理工具的幻影依赖问题",[119],"Node.js","tech","AjqonW4AvfCOfoBw047IkpeSpiJxpWYeNOzAoI20FZM",[123,128],{"title":124,"path":125,"stem":126,"date":127,"type":120,"children":-1},"CSS多行溢出，兼容性比较好的做法","\u002Fposts\u002Fd2e7adb","posts\u002F2024\u002FCSS多行溢出，兼容性比较好的做法","2024-08-02 05:52:01",{"title":129,"path":130,"stem":131,"date":132,"type":120,"children":-1},"策略模式优化多重判断","\u002Fposts\u002Fb0439536","posts\u002F2025\u002F策略模式优化多重判断","2025-10-16",1776347163106]