github vuejs/devtools v9.0.0-beta.0

pre-release3 hours ago

v9.0.0-beta.0

Vue DevTools v9 is a rewrite of the Vue debugging surface on top of Vite DevTools and Devframe by @webfansplz (4df831). It keeps the familiar Components / Pages / Timeline / Pinia / Router / Graph workflow, and ships as a Vite plugin plus a Chromium extension.

See the Migration Guide for setup and plugin API changes.

🚨 Breaking Changes

  • vite: Require Vite 8.3.0+ and a project-level @vitejs/devtools install with devtools: true in the Vite config
  • vite: Stop starting or branding the shared DevTools host from vite-plugin-vue-devtools; register vueDevTools() as a Vue dock only
  • vite: Remove componentInspector and launchEditor. Component inspection lives in the Vue dock; open-in-editor is owned by @vitejs/devtools via vite:core:open-in-editor
  • vite: Move builtinViteDevTools to devtools.builtinDevTools, and move embeddedVisibility / dockPreferences under Vite's devtools config. VueDevToolsDockPreferences is no longer exported
  • api: Remove Vue-level addCustomTab, addCustomCommand, and removeCustomCommand. Use Devframe ctx.docks.register() and ctx.commands.register() instead
  • Drop the overlay shell and split-screen layout from this release line
  • Drop the Vite Assets tab (project file browser)

🚀 Features

  • Rebuild the client as a Vite DevTools dock with Components, Pages, Timeline, Pinia, Router, Graph, Settings, and Command Palette
  • client: Reactivity relationship Graph for the selected component (Vue 3.6+): refs, computed, effects, and their dependency links
  • chrome: Frame-aware MV3 ports (tabId + frameId + documentId) and per-frame runtimes, close #687, #745, #984
  • client: Component search with positive terms, -negative, tag:, file:, and is:favorite, close #304, #801, #1001, #1002
  • client: Restore the selected component across reloads and keep favorites per app, close #467, #601
  • client: Command Palette (Ctrl/Cmd/Alt+K) shared across the Vite dock and Chrome panel
  • client: Optional render/update flash with mount/update duration (off by default), close #678, #699, #827
  • kit: Typed state codec for undefined / "undefined", null, NaN/Infinity, BigInt, Symbol, Date, RegExp, Error, functions, Map/Set, Proxy, cycles, and class instances, close #809, #906, #953, #1087, #1100
  • kit: Keep the v6-style plugin setup API for custom inspectors, _custom.actions, timeline layers, and plugin settings, close #761, #832, #918
  • vite: appendTo accepts string | RegExp | Array<string | RegExp>; inject the client at most once per module, close #586
  • vite: Open in editor only when the host exposes capabilities.openInEditor, close #746, #774, #1093
  • runtime: Highlighter uses a popover so locate still works over open <dialog> elements, close #567, #892
  • client: Recompute action on computed state (triggerRef) for stale/lost-reactivity debugging, close #1041
  • kit: Unaccessed computed values display not accessed without running the getter, close #535

🐞 Bug Fixes

  • chrome: Isolate iframe / micro-frontend apps and tear down ports on navigation, reload, BFCache, frame detach, and panel close, close #445, #926
  • chrome: Skip non-HTML documents (XML, downloads, unsupported schemes), close #505
  • kit: Isolate plugin inspector/layer IDs per plugin + app; a failing plugin no longer takes down the client, close #694
  • kit: Prevent component/inspector state from leaking across selection, unmount, and reconnect, close #668, #689, #1111
  • kit: Store as global variable ($tempN) exposes the live runtime handle instead of a truncated preview
  • client: Do not render ordinary state strings as HTML, close #696
  • kit: One owner per runtime listener so reconnect/HMR does not duplicate keyboard or component events, close #648
  • kit: Isolate malformed custom timeline payloads to a single event, close #728
  • client: Keep expand/collapse state when the tree filter changes; still match KeepAlive inactive children, close #787, #888, #1018
  • client: Restore a horizontal scrollbar on the component tree, close #1001
  • client: Tree role=tree / treeitem with roving focus, close #1018
  • client: Use a font that distinguishes 0 / O / 1 / I / l on component tags, close #1124
  • rpc: Separate Chrome and Vite channels so a dual install no longer hijacks the other inspector, close #1004
  • runtime: Remove locator overlay/listeners on cancel, route change, panel close, and dispose, close #1058
  • runtime: Locator mouseover uses capture so nested components still highlight through @mouseover.stop, close #487
  • kit: Collect setup state from devtoolsRawSetupState / setupState / expose() when setup() returns a render function or JSX defineComponent, close #376, #853
  • vite: Use Vite's resolved base for dock/client routes, close #803, #824, #914, #1013
  • vite: Do not subscribe to or parse unrelated HMR payloads, close #1057
  • vite: Drop vite-plugin-inspect / vite-hot-client / vite-dev-rpc, close #1068

⚡ Performance

  • perf(kit): Load component trees by depth and expand on demand instead of repeatedly refreshing the full tree; skip metadata and scheduled work for updates outside the visible tree unless their state is inspected. Related: #791
  • perf(kit): Use lazy state previews and paged children to avoid serializing entire large values on first inspection. Closes #912 with lazy reads rather than streaming JSON
  • perf(kit): Reduce batch mount/unmount bookkeeping with set-based child links; pair performance events by instance identity so registration cannot strand end events in a strongly held queue
  • perf(kit): Yield scheduled work after a 4ms slice and apply a shared Timeline rate limit before encoding built-in or plugin payloads. Bound tree depth, update debounce, Timeline buffers, and transport message size/backpressure
  • perf(client): Virtualize trees/lists, reuse the index for attribute-only tree patches, and cap pending Timeline events and history at 5,000 each. Process at most 250 entries per batch and show dropped-event markers. Closes #901
  • perf(runtime): Gate collection on client attachment and allow Timeline recording/layers to be disabled. Related: #997

Remaining validation: #791 still needs representative large-app interaction checks; #997 is addressed by deferred collection and layer controls, not fully deferred runtime injection. Browser/network/GPU and long-session reports (#709, #806, #817, #835, #909) remain outside the closure claims. Manual component exclusion (#898) and Timeline JSON export (#1043) are not implemented here.

v8 vs v9 benchmark — ~10K components

Sample: 11,112 Vue components in a tree with 10 children per branch, plus 10,000 root-state records. Latest v8 main vs v9, on Apple M3 Pro / 18 GB RAM / macOS, headless Chrome, Node.js 24, and the same Vue 3.5 runtime. Timings are medians of five runs after warm-up.

Measurement v8 v9
Open panel → component tree visible 540.4ms 188.9ms
Batch update → inspected state painted 810.9ms 174.8ms
Main-thread CPU during batch update 385.2ms 111.7ms
Mount 11,111 components → tree visible 694.0ms 298.3ms
Select root component → state painted 98.4ms 87.6ms
Expand one branch → children painted 66.9ms 100.2ms
Stop Timeline recording during event flood 3,577.8ms 31.1ms
Initial tree payload 2,064,622 bytes 2,187 bytes
Initial state payload 1,480,712 bytes 10,217 bytes

UI timings use the real iframe panels and include RPC, deferred refresh, and painting, rather than stopping at Vue nextTick. Main-thread CPU covers the same 1.1-second update window. Mount starts from an empty tree; component tests have Timeline recording off.

Timeline uses the same scheduled producer (250 emits every 50ms) and each version's default collection policy. This measures stop-button responsiveness, not equal event throughput: v9 drops excess events, while v8's producer also slows under load.

Initial payloads measure the first response, not full-tree expansion: v9 returns 12 tree nodes and lazy state previews. This reduces initial work but can make an individual branch expansion slower, as shown above.

    View changes on GitHub

Don't miss a new devtools release

NewReleases is sending notifications on new releases.