Vue DevTools v9.0.0-beta.0 发布:基于 Vite DevTools 重写
译注:本文翻译自 Vue DevTools 官方 GitHub Release,原文链接见文末。发布日期为 2026-09-22。
Vue DevTools v9 是对 Vue 调试界面的重写,构建于 Vite DevTools 与 Devframe 之上,作者为 @webfansplz(commit 4df831)。它保留了开发者熟悉的 Components / Pages / Timeline / Pinia / Router / Graph 工作流,并以 Vite 插件加 Chromium 扩展两种形式发布。
安装方式与插件 API 的变更请参阅迁移指南。
🚨 破坏性变更
- vite:要求 Vite 8.3.0+,并在项目级安装
@vitejs/devtools,且在 Vite 配置中设置devtools: true。 - vite:
vite-plugin-vue-devtools不再启动或标识共享的 DevTools 宿主;vueDevTools()仅注册为 Vue dock。 - vite:移除
componentInspector与launchEditor。组件检查功能移至 Vue dock;在编辑器中打开由@vitejs/devtools通过vite:core:open-in-editor负责。 - vite:
builtinViteDevTools移至devtools.builtinDevTools,embeddedVisibility/dockPreferences移至 Vite 的devtools配置下。VueDevToolsDockPreferences不再导出。 - api:移除 Vue 层面的
addCustomTab、addCustomCommand与removeCustomCommand。请改用 Devframe 的ctx.docks.register()与ctx.commands.register()。 - 本发布线移除 overlay shell 与分屏布局。
- 移除 Vite 的 Assets 标签页(项目文件浏览器)。
🚀 新特性
- 将客户端重建为 Vite DevTools dock,包含 Components、Pages、Timeline、Pinia、Router、Graph、Settings 与 Command Palette。
- client:为选中组件提供响应式关系 Graph(Vue 3.6+):refs、computed、effects 及其依赖链接。
- chrome:支持 frame 感知的 MV3 端口(
tabId+frameId+documentId)与逐 frame 运行时,关闭 #687、#745、#984。 - client:组件搜索支持正向词、
-negative、tag:、file:与is:favorite,关闭 #304、#801、#1001、#1002。 - client:跨刷新恢复选中组件,并按应用保留收藏,关闭 #467、#601。
- client:Command Palette(
Ctrl/Cmd/Alt+K)在 Vite dock 与 Chrome 面板间共享。 - client:可选的渲染/更新闪烁提示,含挂载/更新耗时(默认关闭),关闭 #678、#699、#827。
- kit:为
undefined/"undefined"、null、NaN/Infinity、BigInt、Symbol、Date、RegExp、Error、函数、Map/Set、Proxy、循环引用与类实例提供带类型的 state codec,关闭 #809、#906、#953、#1087、#1100。 - kit:为自定义 inspector、
_custom.actions、timeline 层与插件设置保留 v6 风格的插件安装 API,关闭 #761、#832、#918。 - vite:
appendTo接受string | RegExp | Array<string | RegExp>;每个模块最多注入一次客户端,关闭 #586。 - vite:仅当宿主暴露
capabilities.openInEditor时才支持在编辑器中打开,关闭 #746、#774、#1093。 - runtime:高亮器改用 popover,使定位在打开的
<dialog>元素上仍可用,关闭 #567、#892。 - client:对 computed 状态提供重新计算操作(
triggerRef),用于调试失效/丢失响应式的问题,关闭 #1041。 - kit:未访问的 computed 值显示
not accessed,且不运行 getter,关闭 #535。
🐞 问题修复
- chrome:隔离 iframe / 微前端应用,并在导航、刷新、BFCache、frame 分离与面板关闭时拆除端口,关闭 #445、#926。
- chrome:跳过非 HTML 文档(XML、下载、不支持的 scheme),关闭 #505。
- kit:按插件 + 应用隔离插件 inspector/layer ID;某个插件出错不再拖垮整个客户端,关闭 #694。
- kit:防止组件/inspector 状态在选中、卸载与重连之间泄漏,关闭 #668、#689、#1111。
- kit:Store as global variable(
$tempN)暴露实时运行时句柄,而非截断的预览。 - client:不再将普通状态字符串渲染为 HTML,关闭 #696。
- kit:每个运行时监听器只有一个所有者,使重连/HMR 不再重复键盘或组件事件,关闭 #648。
- kit:将格式错误的自定义 timeline 负载隔离到单个事件,关闭 #728。
- client:树过滤器变化时保留展开/折叠状态;仍匹配 KeepAlive 的非活跃子节点,关闭 #787、#888、#1018。
- client:恢复组件树的水平滚动条,关闭 #1001。
- client:树使用
role=tree/treeitem与 roving focus,关闭 #1018。 - client:组件标签使用可区分
0/O/1/I/l的字体,关闭 #1124。 - rpc:分离 Chrome 与 Vite 通道,双重安装不再劫持另一个 inspector,关闭 #1004。
- runtime:在取消、路由变化、面板关闭与 dispose 时移除定位 overlay/监听器,关闭 #1058。
- runtime:定位器
mouseover使用捕获,使嵌套组件在@mouseover.stop下仍能高亮,关闭 #487。 - kit:当
setup()返回渲染函数或 JSXdefineComponent时,从devtoolsRawSetupState/setupState/expose()收集 setup 状态,关闭 #376、#853。 - vite:dock/client 路由使用 Vite 解析后的
base,关闭 #803、#824、#914、#1013。 - vite:不再订阅或解析无关的 HMR 负载,关闭 #1057。
- vite:移除
vite-plugin-inspect/vite-hot-client/vite-dev-rpc,关闭 #1068。
⚡ 性能
- perf(kit):按深度加载组件树并按需展开,而非反复刷新整棵树;对可见树之外的更新跳过元数据与调度工作,除非其状态被检查。相关:#791。
- perf(kit):使用惰性状态预览与分页子节点,避免首次检查时序列化整个大值。以惰性读取而非流式 JSON 关闭 #912。
- perf(kit):用基于集合的子链接减少批量挂载/卸载的记账;按实例身份配对性能事件,使注册不会将结束事件滞留在强引用队列中。
- perf(kit):在 4ms 时间片后让出调度工作,并在编码内置或插件负载前应用共享的 Timeline 速率限制。限制树深度、更新防抖、Timeline 缓冲与传输消息大小/背压。
- perf(client):虚拟化树/列表,复用索引处理仅属性变化的树补丁,并将待处理 Timeline 事件与历史各限制为 5,000 条。每批最多处理 250 条,并显示丢弃事件标记。关闭 #901。
- perf(runtime):仅在客户端附加时进行收集,并允许禁用 Timeline 录制/层。相关:#997。
剩余验证:#791 仍需有代表性的大型应用交互检查;#997 通过延迟收集与层控制解决,而非完全延迟运行时注入。浏览器/网络/GPU 与长时间会话相关报告(#709、#806、#817、#835、#909)不在本次关闭声明范围内。手动排除组件(#898)与 Timeline JSON 导出(#1043)未在此实现。
v8 与 v9 基准对比 — 约 1 万个组件
样本:一棵包含 11,112 个 Vue 组件的树,每个分支 10 个子节点,外加 10,000 条根状态记录。对比最新 v8 main 与 v9,环境为 Apple M3 Pro / 18 GB RAM / macOS、无头 Chrome、Node.js 24,以及相同的 Vue 3.5 运行时。时间为预热后五次运行的中位数。
| 测量项 | v8 | v9 |
|---|---|---|
| 打开面板 → 组件树可见 | 540.4ms | 188.9ms |
| 批量更新 → 被检查状态绘制完成 | 810.9ms | 174.8ms |
| 批量更新期间主线程 CPU | 385.2ms | 111.7ms |
| 挂载 11,111 个组件 → 树可见 | 694.0ms | 298.3ms |
| 选中根组件 → 状态绘制完成 | 98.4ms | 87.6ms |
| 展开一个分支 → 子节点绘制完成 | 66.9ms | 100.2ms |
| 事件洪峰期间停止 Timeline 录制 | 3,577.8ms | 31.1ms |
| 初始树负载 | 2,064,622 bytes | 2,187 bytes |
| 初始状态负载 | 1,480,712 bytes | 10,217 bytes |
UI 计时使用真实 iframe 面板,包含 RPC、延迟刷新与绘制,而非止步于 Vue nextTick。主线程 CPU 覆盖相同的 1.1 秒更新窗口。挂载从空树开始;组件测试关闭 Timeline 录制。
Timeline 使用相同的调度生产者(每 50ms 发出 250 条),并采用各版本的默认收集策略。这测量的是停止按钮的响应速度,而非相同的事件吞吐量:v9 会丢弃多余事件,而 v8 的生产者在负载下也会变慢。
初始负载测量的是首次响应,而非整树展开:v9 返回 12 个树节点与惰性状态预览。这减少了初始工作量,但可能使单个分支展开变慢,如上表所示。