教你一招什么叫pnpm依赖提升

474 阅读3分钟

前言

前段时间在做公司内部lint包的时候,在集成到目标项目过程中出现了vscode插件无法正确识别依赖包的问题,导致功能失效

依赖提升

前置知识点

众所可能大家都周知,pnpm对于根路径下的package.json中显示声明的依赖会安装在node_modules的一级目录,而对于间接依赖,则会放在node_modules/.pnpm目录下

可能引发的问题

那这样的机制对于开发会有什么样的问题呢?

不知道大家用过Taro没有,Taro是可以以string[]的形式引入插件的,查找机制是通过声明的插件名称在node_modules的目录中去匹配依赖,也就是说这个逻辑是写在Taro源码中的

设想这样一个场景:我们对Taro配置做了一层抽象,其中用到了一些插件包BCD,把这些插件包作为依赖项放在了Taro的配置包A里,这时候在目标工程中安装A包的时候,包BCD作为间接依赖被安装在node_modules/.pnpm目录下,导致Taro查找不到这些插件包,那这样就出现了功能问题

lint包的问题排查

在做lint包的时候,我把eslintprettierstylelint声明为lint包的依赖,这样做有两个收益:

  1. 我们可以在lint包做统一的版本管理,在做渐进式升级的时候只需要升级lint包即可
  2. 接入方就不需要再安装一次这些lint依赖

安装完出现了一个出乎认知外的问题,eslintprettier依赖安装在了一级目录下,而stylelint则乖乖的躺在了.pnpm目录下

image-20250304141634668.pngimage-20250304141712708.png

哦吼~这是个什么情况?而且这样的一个目录结构还导致了另外一个问题,因为stylelint依赖不是放在一级目录下,导致vscodestylelint插件报错

image-20250304143222539.png

对于这种超出认知外的问题是最难受的,因为连问题描述都写不出来,查都查不了。不过我们现在有AIkimi启动!!!

  1. 将依赖关系和node_modules的依赖截图给AI,让其分析为什么eslint等非直接依赖会安装在pnpm的一级依赖中

  2. 回答中没有有效信息,反问为什么stylelint没有提升

  3. 回答分析可能是public-hoist-pattern的原因,但我什么内容都没配置

  4. 然后将lock文件和.modules.yaml文件发给AI.modules.yaml是放在node_modules目录下,用于定义依赖的解析规则和安装路径),让其排查stylelint为什么没有提升

  5. 回答是.modules.yaml文件中publicHoistPattern自动配置了eslintprettier,缺失了stylelint,所以导致stylelint没有提升到一级依赖,这是pnpm内部提升算法自动添加的!

image-20250304145440307.png

  1. 最后在.npmrceslintprettierstylelint都配置到public-hoist-pattern,还有另外一种方案:在pnpm-workspace.yaml配置public-hoist-pattern

image-20250304145459365.png

总结

  1. pnpm会将一级依赖安装在node_modules一级目录下,间接依赖会安装在node_modules/.pnpm目录下,但不是绝对的
  2. pnpm内部存在依赖提升(hoisting)的算法机制。依赖提升是 pnpm 用来解决依赖版本冲突和重复安装问题的一种方法,它将共享依赖提升到一个公共的位置,使得所有依赖它们的包都能访问到同一个版本的依赖项。
  3. 可以通过在.npmrcpnpm-workspace.yaml文件中显式配置public-hoist-pattern,用来强制提升所需依赖

最后,与君共勉