修复 Vue Devtools Open In Editor 找不到 Toolbox WebStorm
Vue / Nuxt Devtools 里的 Open in editor 本来是一个很顺手的入口:点一下组件或文件路径,IDE 直接跳到对应行。最近它在本机突然不好用了,表现是找不到 WebStorm,或者没有打开当前正在用的那套 WebStorm。
本机编辑器发现逻辑和 JetBrains Toolbox 的安装路径没有对上,导致 Devtools 无法找到当前使用的 WebStorm;Vue 组件和 Nuxt 页面本身不需要为此修改。
当前机器上的 WebStorm 是 JetBrains Toolbox 管理的,而且正在运行的是带版本号的应用包:
~/Applications/WebStorm 2026.1.3.app/Contents/MacOS/webstorm
但 Nuxt Devtools 最后调用的是 launch-editor,它内置的 macOS WebStorm 入口是:
/Applications/WebStorm.app/Contents/MacOS/webstorm
如果本机没有这个标准路径,或者这个路径还指向旧的 Toolbox 应用,Open in editor 就会断在打开编辑器这一步。
修复本机 WebStorm 启动入口
文章配套的 修复脚本 可以直接查看源码。
建议先下载,看一眼,再执行。脚本会改本机 WebStorm 启动入口,不碰项目代码:
curl -fsSLO https://shengsheng.fun/files/vue-devtools-webstorm-toolbox-open-in-editor/scripts/fix-vue-devtools-webstorm-link.sh
bash fix-vue-devtools-webstorm-link.sh
如果想顺手验证能不能打开某个文件,可以带 --open:
bash fix-vue-devtools-webstorm-link.sh --open "$PWD/nuxt.config.ts:1:1"
脚本做的事情很窄:
- 用
ps找正在运行的WebStorm*.app/Contents/MacOS/webstorm;同时运行多个不同版本时停止,避免随意选一个。没有运行中的版本时,才按应用目录修改时间选择已安装候选,执行后需核对版本。 /Applications/WebStorm.app已经是软链时更新整个 app 链接;它是包含Info.plist的真实应用包时保持原样,不改包内二进制。- 标准入口缺失或只是没有
Info.plist的壳目录时,补二进制软链;如果壳目录内部没有写权限,就备份壳目录,再链接整个目标 app。 - 如果
~/Library/Application Support/JetBrains/Toolbox/scripts/webstorm是 Toolbox 自动生成的脚本,也先备份,再替换成同一个软链。
Nuxt 配置也不需要改,修复范围只在本机的 WebStorm 启动入口。
为什么是这个路径
Nuxt Devtools 处理 Open in editor 时,会把传进来的路径补成真实文件路径,再调用 launch-editor:
// @nuxt/devtools/dist/chunks/module-main.mjs:10464
let editor = getOptions()?.behavior.openInEditor ?? void 0;
if (editor === "auto")
editor = void 0;
await import('launch-editor').then((r) => (r.default || r)(path + suffix, editor));
如果 Devtools 配的是自动模式,launch-editor 会先看当前运行中的编辑器进程;如果指定了编辑器,例如 webstorm,它就直接尝试用这个命令打开文件。
问题出在 macOS 的 WebStorm 候选表。launch-editor@2.14.0 里 WebStorm 的映射是:
// launch-editor/editor-info/macos.js:39
module.exports = {
'/Applications/WebStorm.app/Contents/MacOS/webstorm':
'/Applications/WebStorm.app/Contents/MacOS/webstorm',
}
它的进程匹配逻辑也围绕这个标准路径做判断:
// launch-editor/guess.js:43
const processNameWithoutApplications = processName.replace('/Applications', '')
if (output.indexOf(processNameWithoutApplications) !== -1) {
if (processName !== COMMON_EDITORS_MACOS[processName]) {
return [COMMON_EDITORS_MACOS[processName]]
}
const runningProcess = processList.find((procName) =>
procName.endsWith(processNameWithoutApplications),
)
if (runningProcess !== undefined) {
return [runningProcess]
}
}
这段逻辑能覆盖一种常见情况:应用不在 /Applications,但包名仍然叫 WebStorm.app。比如 ~/Applications/WebStorm.app/Contents/MacOS/webstorm 仍然包含 /WebStorm.app/Contents/MacOS/webstorm,所以能被认出来。
但 Toolbox 有时会把稳定版放成带版本号的目录:
~/Applications/WebStorm 2026.1.3.app/Contents/MacOS/webstorm
这个路径里没有 /WebStorm.app/Contents/MacOS/webstorm 这一段。自动识别就很容易跳过 WebStorm,或者落到别的正在运行的编辑器上。即使手动指定 webstorm,也要看 PATH 里的 webstorm 命令是不是指向当前真实版本。
修复点落在本机编辑器入口:补齐缺失的标准路径,或更新已有软链,让它指向目标 Toolbox 版本。已经完整安装的另一个 WebStorm 应用包需要保留,通过明确指定 webstorm 命令选择本次使用的版本。
标准路径和 PATH 命令是两个独立入口。标准路径是完整的其他版本时,脚本会保留它;Toolbox 命令可以指向本次目标版本。不要仅凭标准路径存在,就认定 Devtools 打开的一定是当前版本。
launch-editor 的自动识别依赖当前进程名。如果 WebStorm 已经通过 Toolbox 的带版本号路径启动,进程里看到的仍然可能是 ~/Applications/WebStorm 2026.1.3.app/...,自动模式未必能反推出 WebStorm.app。最稳的做法是让 Devtools 明确使用 webstorm,或者启动 dev server 时带上:
LAUNCH_EDITOR=webstorm pnpm dev
这条环境变量会被 launch-editor 优先读取,比自动猜正在运行的编辑器更稳定。
执行前先检查下载到本地的完整脚本。查找逻辑需要保留可执行路径里的空格,并在替换 Toolbox 生成入口前备份。完整内容见编辑器启动入口脚本弹窗。
执行后怎么确认
脚本跑完会打印当前使用的 WebStorm 版本,以及两个入口的状态。重点看这几行:
使用 WebStorm 入口:/Users/me/Applications/WebStorm 2026.1.3.app/Contents/MacOS/webstorm
WebStorm 2026.1.3
已更新软链:/Applications/WebStorm.app/Contents/MacOS/webstorm -> /Users/me/Applications/WebStorm 2026.1.3.app/Contents/MacOS/webstorm
如果旧入口目录没有内部写权限,输出会变成下面这样:
旧 WebStorm.app 壳目录已备份:/Applications/WebStorm.app.backup-20260611-203000
已创建标准 WebStorm.app 软链:/Applications/WebStorm.app -> /Users/me/Applications/WebStorm 2026.1.3.app
Toolbox 命令的复查仍然应该指向当前版本:
复查 PATH 中的 webstorm:/Users/me/Library/Application Support/JetBrains/Toolbox/scripts/webstorm
WebStorm 2026.1.3
也可以手动查:
ls -l /Applications/WebStorm.app/Contents/MacOS/webstorm
webstorm --version
如果 webstorm --version 输出的是当前正在用的版本,再用 LAUNCH_EDITOR=webstorm 启动 Nuxt dev server,或者在 Devtools 设置里把编辑器指定成 WebStorm,Open in editor 就会走这条已经修好的命令。
也可以用同一个依赖做一次最小验证:
LAUNCH_EDITOR=webstorm node - <<'NODE'
const { createRequire } = require('node:module')
const requireFromNuxtDevtools = createRequire(require.resolve('@nuxt/devtools/package.json'))
const launchEditor = requireFromNuxtDevtools('launch-editor')
launchEditor('/path/to/project/nuxt.config.ts:1:1', (file, message) => {
console.error('launch-editor 打开失败:', file, message)
process.exitCode = 1
})
console.log('已提交打开请求,请在 WebStorm 核对目标文件与行号。')
NODE
命令用于发起一次指定编辑器的调用,回调报告调用错误;没有报错仍需在 WebStorm 里核对实际打开的文件和行号。它不能证明 Devtools 自动模式一定会猜中 WebStorm。
什么时候需要重跑
这类软链是本机补丁。Toolbox 更新 WebStorm、切换 EAP / 稳定版,或者重新生成 ~/Library/Application Support/JetBrains/Toolbox/scripts/webstorm 后,都可能把入口改回去。
再次遇到 Devtools 找不到 WebStorm,先启动目标 WebStorm,再重跑脚本。脚本优先从进程中选择;没有运行中的候选时,会从 ~/Applications 和 /Applications 中按应用目录修改时间取一个已安装候选,这不等于最近使用的版本,要核对打印的路径和版本号。
如果机器上同时开了多个 WebStorm 版本,脚本会停止。只保留目标版本在运行后再执行,避免把启动入口指向另一套稳定版或 EAP。
总结
这次 Open in editor 失效,是 launch-editor 的 WebStorm 发现规则与 Toolbox 带版本号的应用路径没有对上。修复需要区分标准应用路径和 PATH 中的 webstorm 命令:按入口类型补齐或更新链接,保留完整的其他版本应用,再显式指定编辑器并核对实际打开的文件、行号和版本。Toolbox 更新后,入口仍可能需要重新检查。
这个修复只解决本地编辑器入口问题。组件路径不存在、源码映射不对、Devtools 传来的文件路径不是本机路径,仍然要回到项目配置和 Devtools 请求本身查下去。
编辑器启动入口脚本
脚本内容
执行前应检查下载到本地的完整脚本。下面只贴运行中版本的查找逻辑,其他链接处理分支仍以完整文件为准:
standard_webstorm_bin="/Applications/WebStorm.app/Contents/MacOS/webstorm"
toolbox_webstorm_cmd="${HOME}/Library/Application Support/JetBrains/Toolbox/scripts/webstorm"
find_running_webstorm_bin() {
local pid comm candidate=""
while read -r pid comm; do
case "$comm" in
*/WebStorm*.app/Contents/MacOS/webstorm)
if [[ -x "$comm" ]]; then
if [[ -n "$candidate" && "$candidate" != "$comm" ]]; then
echo "检测到多个 WebStorm 入口,请只保留目标版本运行后重试。" >&2
return 1
fi
candidate="$comm"
fi
;;
esac
done < <(ps -axo pid=,comm=)
if [[ -n "$candidate" ]]; then
printf '%s\n' "$candidate"
fi
}
read -r pid comm 会跳过 PID 前面的填充空格,把余下的可执行路径放进 comm,保留路径内部的空格。后续再按标准入口的类型决定是否创建软链,并在替换 Toolbox 生成脚本前做备份。