Windows 下执行 pnpm install 报 EBUSY: resource busy or locked,我最后用这一招解决了

大家好我是舒一笑不秃头,喜欢写作和分享,更多精彩内容~

一次看起来像"依赖安装失败"的问题,最后定位下来,其实不是依赖冲突,也不是版本不兼容,而是 Windows 文件锁 + pnpm 链接机制 触发的经典问题。

如果你也遇到过下面这种报错,这篇文章可以帮你少走很多弯路。


一、问题现场

最近我在本地初始化一个前端 monorepo 项目,执行:

css 复制代码
pnpm i

结果安装过程前面都很顺利,依赖解析、下载、写入基本都完成了,最后却在收尾阶段直接翻车:

makefile 复制代码
EBUSY: resource busy or locked, symlink 
'E:\WebstormProjects\rag_web_ais\node_modules.pnpm\vue-eslint-parser@10.4.0_eslint@8.57.1\node_modules\vue-eslint-parser' 
-> 
'E:\WebstormProjects\rag_web_ais\node_modules\vue-eslint-parser'

完整报错堆栈里还能看到:

vbnet 复制代码
pnpm: EBUSY: resource busy or locked, symlink ...
at async Object.symlink ...
at async forceSymlink ...
at async symlinkHoistedDependency ...

看到这里,很多人第一反应可能是:

  • 是不是依赖冲突了?
  • 是不是 vue-eslint-parser 版本不对?
  • 是不是 lock 文件坏了?
  • 是不是 eslint 版本不兼容?

但实际上,这些方向大概率都不是根因。


二、先说结论:这不是"安装失败",而是"链接失败"

这个问题的关键点在于:

pnpm 并不是像 npm/yarn 那样简单地把所有依赖平铺到 node_modules

它会先把真实依赖存到 .pnpm 目录,再通过符号链接或类似链接机制,把包映射到根 node_modules

也就是说,这次失败不是:

  • 包没下载下来
  • 依赖没解析成功
  • 某个包本身装不上

而是:

.pnpm 里的包已经准备好了,但 pnpm 在把它链接到根 node_modules 时,被 Windows 拦住了。

这个认知很重要。

因为如果你一开始方向就错了,后面会一直在版本、锁文件、依赖树上浪费时间。


三、我怎么判断它不是依赖问题?

我当时进一步做了几步验证。

1. 先看根目录目标是否存在

bash 复制代码
dir node_modules\vue-eslint-parser

结果:

arduino 复制代码
File Not Found

这说明什么?

说明 pnpm 想创建的目标路径 node_modules\vue-eslint-parser,压根还没创建成功。


2. 再看 .pnpm 里面的真实包是否已经存在

bash 复制代码
dir node_modules.pnpm | findstr vue-eslint-parser

结果能看到:

kotlin 复制代码
vue-eslint-parser@10.4.0_eslint@8.57.1
vue-eslint-parser@9.4.3_eslint@8.57.1

这一步几乎已经把问题坐实了:

  • 包已经在 .pnpm
  • 根节点链接没建出来
  • 报错点正好是 symlink

所以根因很清楚:

不是依赖装不上,而是 Windows 在创建链接这一刻返回了 EBUSY


四、为什么 Windows 更容易出现这个问题?

这个问题在 Windows 上很典型,尤其是下面这些场景叠加时:

  • WebStorm / VS Code 正在索引项目
  • TypeScript / ESLint 后台服务扫描 node_modules
  • Windows Defender 实时查杀正在扫描新创建的目录和链接
  • 资源管理器正打开项目目录
  • 某些同步软件或文件监控工具正在监听变更

你表面上看到的是:

makefile 复制代码
EBUSY: resource busy or locked

翻译成人话其实就是:

"我现在想动这个文件/目录/链接,但有别的进程正在碰它。"

这也是为什么很多人反复执行 pnpm install,永远解决不了。

因为你没有处理"占用者",只是不断重试同一个动作。


五、我一开始也走了几条弯路

一开始我也试过这些常规动作:

1. 杀 node.exe

r 复制代码
taskkill /F /IM node.exe

结果:

arduino 复制代码
ERROR: The process "node.exe" not found.

2. 杀 WebStorm64.exe

r 复制代码
taskkill /F /IM WebStorm64.exe

结果:

arduino 复制代码
ERROR: The process "WebStorm64.exe" not found.

这说明两件事:

  • 当前不是前台 Node 进程在占用
  • 也不一定是 WebStorm 主进程名直接锁住

也就是说, "占用者存在"不代表你一定能第一时间猜对进程名。


六、真正关键的排查思路

当时我把问题拆成了两部分去判断:

第一类:是不是残留目录导致的?

比如之前失败后留下了半成品目录,下一次安装冲突。

但检查后发现:

  • 根节点 node_modules\vue-eslint-parser 不存在
  • 删除它时提示找不到文件

说明不是"旧目标没删干净"。


第二类:是不是在创建链接时被锁住了?

这一类和错误现象完全吻合:

  • .pnpm 内部包存在
  • 根层链接不存在
  • 失败点是 symlink
  • 报错是 EBUSY

所以我最后把排查重点从"依赖本身"切换到了:

Windows 文件锁 + pnpm 链接机制兼容性


七、最后真正解决我的方案:切换为 hoisted linker

我最后采用的方式非常简单:

在项目根目录 .npmrc 中加一行:

ini 复制代码
node-linker=hoisted

然后删掉 node_modules,重新安装:

arduino 复制代码
rmdir /S /Q node_modules
pnpm install

结果:直接通过。


八、为什么这个方案有效?

因为默认情况下,pnpm 更依赖它自己的链接式 node_modules 结构。

而我这次出问题的恰恰就是"根层链接创建"这一步。

切换成:

ini 复制代码
node-linker=hoisted

之后,node_modules 的组织方式会更接近传统的扁平安装结构,很多 Windows 下的链接创建问题就被绕开了。

你可以把它理解成:

  • 默认模式:更严格、更节省空间、链接更多
  • hoisted 模式:兼容性更强,尤其适合某些 Windows 环境

所以这不是"乱改配置",而是一个很典型的环境兼容性兜底策略


九、哪些信息看起来很吓人,但其实不是主因?

安装日志里还有很多 warning,比如:

  • DeprecationWarning: url.parse()
  • deprecated eslint
  • deprecated vue-i18n
  • deprecated subdependencies found

这些都很容易把人带偏。

但这类 warning 的特点是:

  • 它们是告警,不是中断点
  • 它们不会直接导致 EBUSY
  • 它们和"资源被占用"不是一个问题域

真正导致安装终止的,是最后那个:

perl 复制代码
EBUSY ... symlink ...

所以遇到这类日志时,一定要学会抓主因,不要被"满屏 warning"带跑。


十、给大家一个最短解决路径

如果你在 Windows 下执行 pnpm install,遇到类似这种错误:

makefile 复制代码
EBUSY: resource busy or locked, symlink ...

我建议你直接按下面顺序处理。

方案一:先尝试常规清理

arduino 复制代码
rmdir /S /Q node_modules
pnpm store prune
pnpm install

如果不行,再继续。


方案二:直接切换为 hoisted linker

.npmrc 中加:

ini 复制代码
node-linker=hoisted

然后重新安装:

arduino 复制代码
rmdir /S /Q node_modules
pnpm install

这个是我最终解决问题的方案。


方案三:检查是否有后台进程占用

重点怀疑这些:

  • Windows Defender
  • IDE 索引进程
  • 资源管理器
  • 同步软件
  • 文件监控工具

如果你想更严谨地查,可以用资源监视器搜项目目录名,或者搜报错里的包名。


十一、我的建议:什么时候该用这个方案?

适合直接上 node-linker=hoisted 的情况

  • 你在 Windows 环境开发
  • 项目是 monorepo
  • pnpm install 经常在链接阶段报错
  • 你当前目标是先把环境稳定装起来

先别急着改的情况

  • 你在 Linux / macOS
  • 团队对 pnpm 默认结构依赖很强
  • 当前只是偶发一次文件锁问题
  • 你更想优先治理 IDE/杀毒/同步软件占用

也就是说:

node-linker=hoisted 更像是一种工程上的稳定性兜底方案,而不是唯一正确答案。


十二、这次问题给我的最大启发

很多安装问题,表面上看是"包管理器报错",但本质上可能是:

  • 操作系统文件锁
  • 工具链目录结构机制
  • IDE/安全软件/同步进程的干扰
  • 环境兼容性问题

真正的排障思路应该是:

1. 先判断失败发生在哪一层

  • 依赖解析?
  • 包下载?
  • 文件写入?
  • 链接创建?

2. 再判断是"内容问题"还是"机制问题"

  • 是版本冲突?
  • 还是文件系统行为?

3. 最后再决定是"修根因"还是"换路径"

  • 治理 Defender / IDE 占用
  • 或者改用 hoisted 这种更兼容的模式

这比一上来就删锁文件、换镜像、降版本,要高效得多。


十三、最终结论

这次问题的本质不是:

  • vue-eslint-parser 有问题
  • eslint 有问题
  • pnpm 坏了
  • 依赖冲突了

而是:

Windows 环境下,pnpm 在创建根层链接时被系统占用机制拦住了。

我最终通过下面这行配置解决:

ini 复制代码
node-linker=hoisted

然后重新安装,问题消失。


十四、给同样踩坑同学的一句话建议

如果你在 Windows 下遇到:

makefile 复制代码
EBUSY: resource busy or locked, symlink ...

不要一上来怀疑依赖版本。

先想一件事:

"是不是包已经装好了,只是在建立链接的时候被系统锁住了?"

一旦你从这个角度切进去,定位速度会快很多。


十五、可直接复制的最终解决方案

ini 复制代码
# .npmrc
node-linker=hoisted
arduino 复制代码
rmdir /S /Q node_modules
pnpm install

十六、结尾

如果你也在 Windows + pnpm + monorepo 环境里踩过类似的坑,欢迎在评论区聊聊你遇到的是:

  • EBUSY
  • EPERM
  • symlink
  • rename
  • unlink

这类问题我后面也可以继续整理一篇 Windows 前端工程环境疑难杂症排障手册

相关推荐
龙月2 小时前
Gitlab迁移与升级技术方案
前端·后端
用户223586218202 小时前
核心三角-Command Agent Skill - claude_0x02
前端
竹林8182 小时前
在NFT项目中集成IPFS:从Pinata上传到前端展示的完整踩坑指南
前端·javascript
吴声子夜歌2 小时前
Vue3——渲染函数
前端·vue.js·vue·es6
Hello--_--World2 小时前
ES15:Object.groupBy() 和 Map.groupBy()、Promise.withResolvers() 相关知识点
开发语言·前端·javascript
Cache技术分享2 小时前
386. Java IO API - 监控目录变化
前端·后端
Hooray2 小时前
管理后台框架 AI 时代的版本答案,Fantastic-admin 6.0 它来了!
前端·前端框架·ai编程
2501_913680003 小时前
Vue3项目快速接入AI助手的终极方案 - 让你的应用智能升级
前端·vue.js·人工智能·ai·vue·开源软件
开开心心_Every3 小时前
动图制作工具,拆分转视频动态照离线免费
运维·前端·人工智能·edge·pdf·散列表·启发式算法