同事:为什么用了pnpm后线上打包失败了?

前言

大家好,我是evanryuu🫠

这次给大家分享一个我们前些天经历的pnpm缓存导致线上打包失败的抽象经历。

事件过程

我们的项目部署在AWS Amplify上,跟大部分公司一样是在线上进行打包的。

项目里之前是用得npm,前些天换成了pnpm。推到线上测试分支打包,没问题。合并到主分支打包,也没问题。于是我们都觉得没啥问题了。

后来过了两天,有个新的修复要马上上线。但这时候测试服突然打包失败了。

抽象的是,我们在本地打包都没什么问题,不管是npm还是pnpm,不管是已经装好环境的电脑还是重新弄台电脑,本地都打包得很正常。

我看了看线上的报错,是这样的

说实话,看不明白这里是什么问题。所以为了偷懒选择了升级了ts和vue tsc的版本。

当然,错误没有解决,只是从几千行变成了几十行。甚至连报错的信息都没有差很多。但是由于只剩下了几十行,所以排除了很多可能性。

当时线上有一行错误非常显眼

lua 复制代码
failed to load vite.config.ts

我心想:这玩意儿也能failed?啊?怎么可能呢?

然后我的目光移到了另一行报错

kotlin 复制代码
xxx.yy is not a constructor

其实之前几千行报错有很多都是上面这样的,然而现在还有。于是我回去看了下还没更新依赖的报错日志。

我发现里面有很多依赖都经过了 .pnpm 这个文件夹。

原因推测

我们知道pnpm的核心原理就是软硬连接。我们安装的依赖会被pnpm放到一个全局store里,然后在项目里的 node_modules/.pnpm 文件夹则是虚拟store,它会通过硬连接指向全局store。所以不同项目如果有同样的依赖就会指向同样的全局store,也就能节省磁盘空间。

而包与包之间的关系是通过软连接(symbolic link)关联起来的,各位也可以打开pnpm的项目看看node_modules。

而在我们的线上流水线的配置文件中,配置了node_modules的缓存,像下面这样

yml 复制代码
cache:
  node_modules/*

所以第一次合并分支进行线上打包的时候,服务器没有node_modules的缓存,会从头安装一遍依赖,此时虚拟store和全局store关系很正常

但是由于我们设置了缓存,这就导致了第二次打包之后进来有了虚拟store的缓存,但由于全局store没了,所以硬连接指向了一片空白,所以并没有依赖文件。

这也合理地解释了为什么报错全都是 xxx.xx is not a constructor之类的,而且路径基本都会经过 node_modules/.pnpm 。

结果

由于急着上线,所以我们直接取消了node_modules的缓存。神奇的是,pnpm在不缓存的情况下,安装+打包的速度也比有缓存的npm要快。

谨以此文记录下这次神奇的经历。

如果对你有所启发的话,也希望你可以动动小手点一个免费的赞,这会给我的创作带来很大的激励!

如果你觉得这篇文章哪里写的有问题的话,也欢迎你在评论区中指出,我们友好讨论~

相关推荐
AiMan37 分钟前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真40 分钟前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment42 分钟前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan1 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么1 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技1 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue
西安小哥2 小时前
端侧跑大模型,真正的门槛不在参数量:一次 596 秒到 10 秒的压缩路径复盘
前端·人工智能
陈随易2 小时前
Cloudflare 出钱,Vite 团队挑人,44 个维护者分 30 万美元
前端·后端·程序员
恋猫de小郭3 小时前
Flutter THLC 的 WebView 滚动终于从 70 FPS 提升到 120 FPS
android·前端·flutter
严肃小白兔3 小时前
TanStack Router 更新构建工具链:Node.js 兼容性、路由分割与前端工程实践
前端·node.js·状态模式