ARTICLE · 1184120
一次 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 生态时,原生模块的兼容性和构建配置往往是隐藏最深的坑。希望这篇文章能帮你快速定位类似问题,少走弯路。















































































