夜雨聆风学习资料网

ARTICLE · 1184120

一次 DSH 插件安装的踩坑实录与原理剖析

一次 DSH 插件安装的踩坑实录与原理剖析

记录一次在 Windows 下为 DSH 安装本地插件时,从连环报错到最终定位到 “kexec” 配置的完整过程,这是在整个DSH插件过程中从没遇到过的情况。希望这份踩坑记录能帮你少走弯路。

一、背景

目标很简单:安装DSH 插件 dsh-our-free-model。命令如下:

dsh plugin --profile web add C:\Users\Administrator\.dsh\profiles\web\node_modules\dsh-our-free-model

本以为一条命令就能搞定,没想到却开启了一段“报错马拉松”。

二、解决冲突

第一阶段:Corepack 与 pnpm 12 的冲突

第一个拦路虎是:

Error: Cannot find module 'C:\Users\Administrator\AppData\Local\node\corepack\v1\pnpm\12.11.2\bin\pnpm.cjs'

原因:Node.js 自带的 Corepack 试图加载 pnpm 12,但 pnpm 从 v11 开始入口文件已从 pnpm.cjs 改为 pnpm.mjs,v12 更是用 Rust 重写为原生可执行文件。旧版 Corepack 仍在按老路径查找,自然找不到。

解决:绕过 Corepack,直接用 npm 全局安装 pnpm:

npm install -g pnpm@12

第二阶段:Node 版本与 npm 升级的连环坑

在尝试升级 npm 时又遇到:

npm error code EBADENGINE

npm error notsup Required: {"node":"^22.22.2 || ^24.15.0 || >=26.0.0"}

npm error notsup Actual:   {"npm":"10.9.2","node":"v22.16.0"}

原因:npm@12.2.0 要求 Node 版本至少为 22.22.2,而当前是 22.16.0。

教训:不要盲目升级全局 npm,版本匹配很重要。如果只是为了装 pnpm,根本不需要升级 npm。最终用现有 npm 10 直接安装 pnpm 12 即可。

第三阶段:安全软件与文件系统权限的干扰

安装 pnpm 后,dsh plugin add 开始报:

Error: ERR_PNPM_GIT_FETCHER_IO

 -> I/O error during git fetch: 无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。 (os error 225)

原因:Windows Defender 或第三方杀毒软件拦截了 pnpm 通过 git 拉取依赖的操作。

尝试解决:将 pnpm store 路径和 git.exe 加入 Defender 排除项。但执行 Add-MpPreference 时又遇到 PowerShell 执行策略限制:

无法加载文件 ...\pnpm.ps1。未对文件进行数字签名。

解决:修改执行策略为 RemoteSigned:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

第四阶段:PowerShell 中的 npm 幽灵文件

在排查过程中,发现运行 npm 会弹出“打开方式”窗口。Get-Command npm 显示:

Application     npm    0.0.0.0    C:\Windows\system32\npm

原因:C:\Windows\System32 下存在一个无扩展名的残留 npm 文件,PowerShell 优先找到它,却无法执行。

解决:以管理员身份删除该文件:

Remove-Item "C:\Windows\System32\npm" -Force

删除后,Get-Command npm 正确指向 D:\Program Files\nodejs\npm.ps1。

第五阶段:真正的元凶——kexec: true

环境问题逐一解决后,dsh plugin add 仍然报错:

Error: ERR_PNPM_CMD_SHIM_READ_MANIFEST

 -> Failed to read ...\dsh-our-free-model\package.json: 系统无法辨识文件名。 (os error 1921)

尝试了清理 node_modules、pnpm store prune、检查 NTFS 格式、排查软链接,甚至怀疑是符号链接损坏,但问题依旧。

直到我注意到 pnpm-workspace.yaml 中的一段配置:

allowBuilds:

  @google/genai: true

  es5-ext: true

  kexec: true      # ← 强制编译,必然失败

  node-pty: true

  protobufjs: true

抱着试一试的心态,把 kexec: true 改为 false:kexec: false

再次运行安装命令——成功了!

三、原理剖析:为什么 kexec: true 会导致失败?

1. pnpm 的 allowBuilds 是什么?

从 pnpm v10.26 开始,pnpm-workspace.yaml 中的 allowBuilds 字段取代了旧的 onlyBuiltDependencies,用于控制哪些依赖包可以在安装时运行生命周期脚本(如 preinstall、install、postinstall)。

- true:允许该依赖运行构建脚本。

- false:禁止运行构建脚本,但包本身仍会被安装。

这是一个供应链安全机制,防止第三方包在安装时自动执行任意代码。

2. kexec 为何在 Windows 上“必然失败”?

kexec 是一个 Node.js 原生模块,它的功能是用另一个进程替换当前 Node.js 进程,类似于 Unix 的 exec 系统调用。它的源码大量依赖 Unix 特有的系统调用和头文件,官方明确不支持 Windows。

当 kexec: true 时,pnpm 会尝试在 Windows 上编译这个原生模块。编译需要 node-gyp、Visual Studio Build Tools、Python 等环境,而 kexec的源码本身就无法在 Windows 上编译通过,因此构建过程必然失败。

失败后,pnpm 的安装流程被中断,并抛出各种看似无关的错误,例如 ERR_PNPM_CMD_SHIM_READ_MANIFEST 和 os error 1921。这些其实是构建失败后的连锁反应,而非根本原因。

3. 为什么改为 false 就成功了?

设置为 false 后,pnpm 直接跳过了 kexec 的编译步骤。由于 kexec 只是一个间接依赖,跳过它的构建并不会影响主程序的安装与运行。安装流程不再被中断,后续的 shim 创建、manifest 读取等步骤都能正常完成。

四、经验教训与最佳实践

1. 不要盲目开启 allowBuilds 

对于不熟悉的原生模块,尤其是明确不支持 Windows 的包(如 kexec),应保持 false。除非你确认该模块在 Windows 上可编译且必需,否则跳过构建是更安全的选择。

2. Corepack 与 pnpm 12 不兼容 

在 Node 22 等版本上,Corepack 可能无法正确加载 pnpm 12。建议直接用 npm install -g pnpm 或官方独立安装脚本。

3. 注意 Node 与 npm 的版本匹配

升级全局 npm 前先检查引擎要求,避免 EBADENGINE。多数情况下,使用 Node 自带的 npm 版本即可。

4. Windows 安全软件会拦截 pnpm 的 git 操作

将 pnpm store 路径和 git.exe 加入 Defender 排除项,可避免 ERR_PNPM_GIT_FETCHER_IO。

5. 警惕 PATH 中的残留文件

C:\Windows\System32 下的无扩展名 npm 文件会干扰命令解析,导致 PowerShell 弹出“打开方式”。定期检查 Get-Command npm 的指向。

6. PowerShell 执行策略

若遇到“未签名”错误,设置 RemoteSigned 策略即可,无需完全禁用安全机制。

7. 错误信息可能具有误导性 

ERR_PNPM_CMD_SHIM_READ_MANIFEST 和 os error 1921 看似是文件系统或软链接问题,实则由原生模块编译失败引发。排查时应从配置和构建日志入手,而非只盯着表面错误。

六、结语

这次踩坑历时数小时,跨越了 Corepack、Node 版本、安全软件、PowerShell 策略、PATH 残留等多个领域,最终却由一个简单的 kexec: false 画上句号。它提醒我们:在 Windows 下折腾 Node 生态时,原生模块的兼容性和构建配置往往是隐藏最深的坑。希望这篇文章能帮你快速定位类似问题,少走弯路。

相关学习资料