From 5460149f5c29a6f10a97cf5ecd529811aa0a8c4c Mon Sep 17 00:00:00 2001 From: zen010101 <60574100+zen010101@users.noreply.github.com> Date: Thu, 4 Jun 2026 01:00:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=93=E5=BC=80=20W?= =?UTF-8?q?SL=20=E6=96=87=E4=BB=B6=E6=97=B6=E4=B8=BB=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E5=9B=A0=20EISDIR=20=E5=B4=A9=E6=BA=83=20(#172)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 打开 \\wsl.localhost\ 下的文件时,应用会自动把文件所在目录作为工作区并用 chokidar 递归监听。chokidar 遍历到目录中的 Linux 软链接(如 *.so.0)时会对其 lstat,而 Windows/Node 对经 9P 重定向器暴露的 WSL 软链接做 lstat 会返回 EISDIR (底层是 9P 不支持读取该软链接的 reparse 数据,返回 Incorrect function,被 libuv 映射成了 EISDIR)。该错误没有任何地方处理,冒泡成主进程 uncaughtException,于是弹出 "A JavaScript error occurred in the main process" 并使文件区卡死。 修复采用双保险: - workspacePath.ts:isRemoteWorkspacePath 不再依赖 isWindows 做前置短路。该模块运行在 渲染进程(nodeIntegration:false),那里 process.platform 不可用,isWindows 恒为 false,会让原有的 WSL/远程路径防护永远失效。去掉该短路后,防护真正生效,从源头避免对 WSL 目录自动加载工作区与递归监听。UNC 路径(\\wsl.localhost\、\\wsl$\、\\server\share) 本身是 Windows 专有写法,不会出现在其他平台的合法路径里,无需平台判断即可安全识别。 - ipcBridge.ts:给 file watcher 与 directoryWatcher 各补一个 "error" 监听。chokidar 出错时会 emit "error",没有监听器时会冒泡成主进程 uncaughtException。补上后任何 watcher 错误都只记录、不再使应用崩溃,对所有文件系统(不止 WSL)都更健壮。 注:本次修复保证不再崩溃,但 WSL 文件暂时不会自动加载左侧文件树(防护跳过了)。后续会做 第二层改进,让 WSL 文件也能正常显示文件树。 --- src/main/ipcBridge.ts | 13 +++++++++++++ src/renderer/utils/workspacePath.ts | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/ipcBridge.ts b/src/main/ipcBridge.ts index c35b918..7d84fd4 100644 --- a/src/main/ipcBridge.ts +++ b/src/main/ipcBridge.ts @@ -1620,6 +1620,13 @@ export function registerGlobalIpcHandlers() { } } }); + + // chokidar 在监听/遍历出错时会 emit "error";若无监听器,EventEmitter 会把错误 + // 抛成主进程 uncaughtException(例如 \\wsl.localhost\ 下对 Linux 软链接 lstat 返回 + // EISDIR)。这里吞掉并记录,避免整个应用崩溃。 + watcher.on("error", (error) => { + console.warn("[file:watch] watcher error:", error); + }); } // 新增的文件 - 添加到 watcher @@ -1671,6 +1678,12 @@ export function registerGlobalIpcHandlers() { directoryWatcher.on("unlink", notifyChanged); directoryWatcher.on("addDir", notifyChanged); directoryWatcher.on("unlinkDir", notifyChanged); + // chokidar 递归遍历目录时若对某个条目 lstat 失败会 emit "error"。典型场景:监听 + // \\wsl.localhost\ (WSL/9P) 下的目录,对 Linux 软链接(如 *.so.0)lstat 返回 EISDIR。 + // 没有该监听器时错误会冒泡为主进程 uncaughtException 导致崩溃,这里吞掉并记录。 + directoryWatcher.on("error", (error) => { + console.warn("[workspace:watchDirectory] watcher error:", error); + }); }); // 停止监听目录 diff --git a/src/renderer/utils/workspacePath.ts b/src/renderer/utils/workspacePath.ts index 85282af..88fd1c7 100644 --- a/src/renderer/utils/workspacePath.ts +++ b/src/renderer/utils/workspacePath.ts @@ -10,8 +10,14 @@ export function isAbsoluteLocalPath(pathValue: string): boolean { return pathValue.startsWith("/"); } +// 注意:本模块在渲染进程执行(nodeIntegration:false),渲染进程里 process.platform 不可用, +// platform.ts 的 isWindows 会恒为 false。因此这里【不能】用 isWindows 做前置短路,否则本防护 +// 会永远失效——曾导致打开 WSL 文件时仍自动加载工作区,进而对 \\wsl.localhost\ 下的 Linux 软链接 +// (如 librockchip_mpp.so.0)lstat 触发 EISDIR,使主进程未捕获异常崩溃。 +// UNC 路径(\\wsl.localhost\、\\wsl$\、\\server\share)本身是 Windows 专有写法,不会出现在其他 +// 平台的合法路径里,无需平台判断即可安全识别为远程路径。 export function isRemoteWorkspacePath(pathValue: string): boolean { - if (!pathValue || !isWindows) return false; + if (!pathValue) return false; return /^\\\\wsl(?:\$|\.localhost)\\/i.test(pathValue) || /^\\\\(?![?.]\\)/.test(pathValue); }