pnpm10升级的话谨慎些

发表于 2025-06-26
更新于 2025-06-26
分类于 技术专栏
阅读量 10
字数统计 3160

1、背景

3月份突然团队同学说我们的研发平台项目启动失败了,需要我介入排查看一下原因,我按照思路就去看了下构建日志。

这里讲一下我们的项目技术栈是Nestjs + Prisma的后端服务,加上antd的前端服务,一整套全栈。

2、发现问题

去看了下容器的日志,发现:

node:internal/modules/cjs/loader:1222
  throw err;
  ^

Error: Cannot find module '/xxxxxxxx/node_modules/.pnpm/bcrypt@5.1.0/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node'
Require stack:
- /xxxxxxxx/node_modules/.pnpm/bcrypt@5.1.0/node_modules/bcrypt/bcrypt.js
- /xxxxxxxx/main.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1219:15)
    at Module._load (node:internal/modules/cjs/loader:1045:27)
    at TracingChannel.traceSync (node:diagnostics_channel:315:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:215:24)
    at Module.require (node:internal/modules/cjs/loader:1304:12)
    at require (node:internal/modules/helpers:123:16)
    at Object.<anonymous> (/xxxxxxxx/node_modules/.pnpm/bcrypt@5.1.0/node_modules/bcrypt/bcrypt.js:6:16)
    at Module._compile (node:internal/modules/cjs/loader:1504:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1588:10)
    at Module.load (node:internal/modules/cjs/loader:1282:32) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/xxxxxxxx/node_modules/.pnpm/bcrypt@5.1.0/node_modules/bcrypt/bcrypt.js',
    '/xxxxxxxx/main.js'
  ]
}

哦,好像问题很明显啊,就是bcrypt这个包少了一个NAPI文件嘛。

3、查找原因

为什么会少了这个文件呢?之前的不都是好好的吗?按照提示,我去看了下容器里面的文件: image.png

确实没有这个文件,甚至lib目录都没有。好奇怪啊,lib这个目录没有为啥?于是我去看了下bcrypt的包,在package.json中找到bcrypt_lib.node的来历:

1{ 2 "binary": { 3 "module_name": "bcrypt_lib", 4 "module_path": "./lib/binding/napi-v{napi_build_version}", 5 "package_name": "{module_name}-v{version}-napi-v{napi_build_version}-{platform}-{arch}-{libc}.tar.gz", 6 "host": "https://github.com", 7 "remote_path": "kelektiv/node.bcrypt.js/releases/download/v{version}", 8 "napi_versions": [ 9 3 10 ] 11 } 12}

package.json文件的这个binary目录表示,该包编译构建后产出bcrypt_lib,并放在./lib/binding/napi-v{napi_build_version}下,这不是和我们的问题源头路径对上了吗?

那为什么不会产出呢?

4、根本原因

bcrypt的这个配置是这么个流程:

  1. 安装时:当你运行 npm install bcrypt 时

  2. 检查预构建版本:node-pre-gyp 会根据你的系统平台、架构等信息构造下载 URL

  3. 下载二进制文件:尝试从 GitHub releases 下载对应的预构建版本

  4. 备用编译:如果下载失败,会回退到本地编译(--fallback-to-build)

那也就是问题出在pnpm安装bcrypt的时候,没有预构建,于是我去pnpm找一下是否有类似的问题没?

终于被我找到了一篇文章:https://socket.dev/blog/pnpm-10-0-0-blocks-lifecycle-scripts-by-default

文章讲的是pnpm 10.0.0版本以上会默认阻止生命周期脚本以提高安全性,此举旨在减少供应链攻击风险,但引发了关于兼容性和开发者工作流变化的争议。维护者和社区成员提出了改进建议,以平衡安全性和用户体验。

pnpm 10.0.0默认阻止生命周期脚本,需通过package.json中的pnpm.onlyBuiltDependencies字段手动允许特定依赖的脚本执行,此更改旨在应对供应链攻击风险。 此举是对Rspack供应链攻击事件的直接回应,该事件通过postinstall脚本传播恶意加密挖矿软件。 虽然社区多数支持默认阻止脚本,但一些开发者批评此更改破坏了与npm的兼容性,并建议通过可选标志实现类似功能。 支持者认为这是解决设计缺陷的重要一步,尽管会带来用户适应期,并建议通过交互式命令和更清晰的提示减少用户困惑。 除阻止脚本外,pnpm 10还引入了SHA256哈希算法以增强安全性,并更新了pnpm link命令行为。

于是我就按照文章讲的,在package.json中配置:

1{ 2 "pnpm": { 3 "onlyBuiltDependencies": ["bcrypt"] 4 } 5}

再重新编译: image.png

果然这次有bcrypt的安装提示了,我再回头去看之前的执行命令: image.png

原来pnpm已经在命令行有所提示了,告知他们的脚本运行被阻止了,pnpm你这个老六啊!

公众号关注一波~

微信公众号

关于评论和留言

如果对本文 pnpm10升级的话谨慎些 的内容有疑问,请在下面的评论系统中留言,谢谢。

网站源码:linxiaowu66 · 豆米的博客

Follow:linxiaowu66 · Github