chore(deps): upgrade to Vite DevTools v0.4.0 and devframe v0.6.0#1010
chore(deps): upgrade to Vite DevTools v0.4.0 and devframe v0.6.0#1010antfubot wants to merge 3 commits into
Conversation
Bump `@vitejs/devtools` and `@vitejs/devtools-kit` to 0.4.0, which pulls in the devframe 0.6 runtime (official terminals/messages/inspect plugins, crossws transport, OTP/magic-link auth). The plugin-author surface the Nuxt module builds on (`Plugin.devtools.setup`, `DevTools()`, the dock/rpc context, and the kit client) is unchanged, so no module code changes are needed. Dedupe the tree onto a single devtools runtime: force `@vitejs/devtools-kit` to 0.4.0 (vite-plugin-inspect still pins ^0.3.1 but only uses the version-agnostic `defineRpcFunction` passthrough) and align vue on 3.5.39 (required by devtools 0.4) to avoid mixed `@vue/compiler-sfc` versions producing duplicate-import SFC codegen.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
📝 WalkthroughWalkthroughUpdates client RPC registration to use an idempotent helper that chooses between updating existing definitions and registering new handlers. The DevTools E2E fixture initializes client RPC trust before waiting for docks. Vue DevTools messaging now binds to the active dock iframe and rebinds when it is recreated. Workspace dependency exclusions, catalogs, and Vue resolution overrides are updated for newer toolchain releases. Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…evframe 0.6 vite-plugin-inspect 12.0.2 depends on `@vitejs/devtools-kit@^0.4.0`, so the temporary override that forced the kit onto 0.4.0 (to dedupe away the beta.3 → devframe 0.5 runtime) is no longer needed and is removed; the tree now resolves a single devtools-kit / devframe naturally. Also adapt to two devframe 0.6 behaviour changes that broke the e2e run: - Client RPC registration split into `register()` (throws DF0021 if the name exists) and `update()` (throws DF0022 if it does not). Register the Nuxt client's callback functions through a small `has()`-guarded upsert so re-registration no longer throws. - The `devframe:docks` shared state is only fetched once the client is marked trusted. `VITE_DEVTOOLS_DISABLE_CLIENT_AUTH` trusts the server peer (RPC works) but never flips the client-side trust flag, leaving the dock list empty forever, so the e2e fixture now nudges the client trust event to kick off the docks subscription (a no-op in built/preview's static-RPC mode).
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/devtools/client/composables/rpc.ts (1)
40-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting the shared
clientFunctionsiteration.The loop body at lines 40–43 and 67–70 is identical. A small helper would eliminate the duplication and keep both registration paths in sync if the iteration logic ever changes.
♻️ Optional DRY refactor
+function registerAllClientFunctions(client: DevToolsRpcClient) { + for (const [name, handler] of Object.entries(clientFunctions)) { + if (typeof handler === 'function') + upsertClientFunction(client, name, handler) + } +} + async function connectDevToolsRpc(): Promise<DevToolsRpcClient> { try { const client = await getDevToolsRpcClient() rpcClient.value = client - // Register client functions so the server can call them. - for (const [name, handler] of Object.entries(clientFunctions)) { - if (typeof handler === 'function') - upsertClientFunction(client, name, handler) - } + // Register client functions so the server can call them. + registerAllClientFunctions(client) // eslint-disable-next-line no-console console.log('[nuxt-devtools] Connected to Vite DevTools RPC')And in
registerClientFunctions:export async function registerClientFunctions() { const client = rpcClient.value || await connectPromise - for (const [name, handler] of Object.entries(clientFunctions)) { - if (typeof handler === 'function') - upsertClientFunction(client, name, handler) - } + registerAllClientFunctions(client) }Also applies to: 65-71
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/devtools/client/composables/rpc.ts` around lines 40 - 43, Extract the duplicated clientFunctions iteration into a shared helper near the existing registration logic, using the same function-type check and upsertClientFunction call. Replace both loops in the client registration paths, including registerClientFunctions, with this helper so both paths remain synchronized.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/devtools/client/composables/rpc.ts`:
- Around line 40-43: Extract the duplicated clientFunctions iteration into a
shared helper near the existing registration logic, using the same function-type
check and upsertClientFunction call. Replace both loops in the client
registration paths, including registerClientFunctions, with this helper so both
paths remain synchronized.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 282632c6-d519-40ed-a833-4648a73192a1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
packages/devtools/client/composables/client.tspackages/devtools/client/composables/rpc.tspnpm-workspace.yamltests/e2e/fixtures/devtools.ts
… iframe The Pinia / component-inspector panels were stuck on "Connecting..." because `@vue/devtools-kit`'s iframe messaging channel only answers the iframe passed to `setIframeServerContext()`. That call previously lived in the legacy `getIframe()` path, which is dead now that the panel is rendered as an iframe inside Vite DevTools' dock — so the host Vue DevTools backend never learned which iframe to talk to and the applet's RPC heartbeat timed out. Bind the dock iframe (from the Vite DevTools client context) via `setIframeServerContext()` as soon as it mounts, re-pointing if the element is recreated. Fixes the flaky `tab-pinia` e2e spec (previously failing on `main`).
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/devtools/src/runtime/plugins/view/client.ts`:
- Around line 298-313: Update bindVueDevToolsIframe to retain and clear the
polling interval once the dock iframe is found and bound, preventing indefinite
polling and duplicate intervals across repeated setup calls. Preserve rebinding
when the iframe is later recreated by using an appropriate lifecycle mechanism,
such as a MutationObserver or controlled slower retry, while ensuring only one
active polling mechanism exists.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 88a02e95-c6ea-47aa-9b84-6ee57c7e2a0f
📒 Files selected for processing (1)
packages/devtools/src/runtime/plugins/view/client.ts
| function bindVueDevToolsIframe() { | ||
| let bound: HTMLIFrameElement | undefined | ||
| const bind = () => { | ||
| const ctx = getViteDevToolsContext() | ||
| const dockIframe = ctx?.docks?.getStateById?.('nuxt:devtools')?.domElements?.iframe as HTMLIFrameElement | null | undefined | ||
| if (!dockIframe || dockIframe === bound) | ||
| return | ||
| bound = dockIframe | ||
| iframe = dockIframe | ||
| // The channel reads `.contentWindow` lazily on every message, so binding | ||
| // the element once is enough even across in-iframe navigations/reloads. | ||
| setIframeServerContext(dockIframe) | ||
| } | ||
| bind() | ||
| setInterval(bind, 500) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
setInterval is never cleared — resource leak and duplicate-interval risk.
The interval created at line 312 runs indefinitely with no cleanup path. If setupDevToolsClient is invoked more than once (e.g., during HMR or module re-initialization), each call spawns a new 500ms interval that stacks on top of previous ones, causing unbounded polling and redundant setIframeServerContext calls.
Even in the single-invocation case, the interval persists forever after binding succeeds, continually traversing getViteDevToolsContext() and the dock state tree every 500ms for the lifetime of the page.
Consider capturing the interval handle and clearing it when the dock iframe is found, then re-establishing polling only if the element is later recreated (e.g., via a MutationObserver or a slower heartbeat). At minimum, guard against duplicate intervals:
🔒 Proposed fix: clear interval after binding, use MutationObserver for recreation
function bindVueDevToolsIframe() {
let bound: HTMLIFrameElement | undefined
+ let timer: ReturnType<typeof setInterval> | undefined
+
const bind = () => {
const ctx = getViteDevToolsContext()
const dockIframe = ctx?.docks?.getStateById?.('nuxt:devtools')?.domElements?.iframe as HTMLIFrameElement | null | undefined
if (!dockIframe || dockIframe === bound)
return
bound = dockIframe
iframe = dockIframe
setIframeServerContext(dockIframe)
+ // Once bound, stop the initial fast-poll interval and watch for
+ // future iframe recreation via MutationObserver instead.
+ if (timer) {
+ clearInterval(timer)
+ timer = undefined
+ }
+ const observer = new MutationObserver(() => bind())
+ observer.observe(document.body, { childList: true, subtree: true })
}
- bind()
- setInterval(bind, 500)
+ bind()
+ timer = setInterval(bind, 500)
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/devtools/src/runtime/plugins/view/client.ts` around lines 298 - 313,
Update bindVueDevToolsIframe to retain and clear the polling interval once the
dock iframe is found and bound, preventing indefinite polling and duplicate
intervals across repeated setup calls. Preserve rebinding when the iframe is
later recreated by using an appropriate lifecycle mechanism, such as a
MutationObserver or controlled slower retry, while ensuring only one active
polling mechanism exists.
Description
Upgrades the Vite DevTools integration to
@vitejs/devtools/@vitejs/devtools-kitv0.4.0, which adopts the devframe 0.6 runtime — the official@devframes/plugin-terminals/plugin-messages/plugin-inspectbuilt-ins, thecrosswsWebSocket transport bound to Vite's dev-server route, and the new OTP / magic-link auth handshake — and pullsvite-plugin-inspectup to v12.0.2 so the whole tree resolves a single devtools-kit / devframe runtime.The plugin-author surface the Nuxt module builds on is unchanged upstream (
Plugin.devtools.setup,DevTools(), the dock / rpc / panel context, and the kit client API), so no module wiring changes are needed beyond adapting to a couple of devframe 0.6 runtime behaviour changes.Dependencies
@vitejs/devtoolsand@vitejs/devtools-kitcatalogs to^0.4.0, andvite-plugin-inspectto^12.0.2(which itself targets devtools-kit^0.4.0). Refresh theminimumReleaseAgeExcludepins for the devframe 0.6 / devtools 0.4 /@devframes/plugin-*packages.3.5.39(required by devtools 0.4) to avoid mixed@vue/compiler-sfcversions producing duplicate-import SFC codegen during the UI-kit build.vite-plugin-inspect@12.0.2depends on devtools-kit^0.4.0, so the temporary@vitejs/devtools-kitoverride is dropped — the tree resolves a single@vitejs/devtools-kit@0.4.0/devframe@0.6.0/@devframes/hub@0.6.0.devframe 0.6 adaptations
register()(throwsDF0021if the name exists) andupdate()(throwsDF0022if it does not). The Nuxt client's callback registration now goes through ahas()-guarded upsert helper.devframe:docksshared state is only fetched once the client is trusted (rpc:is-trusted:updated).VITE_DEVTOOLS_DISABLE_CLIENT_AUTHtrusts the server peer (RPC works) but never flips the client flag, so the dock list stayed empty and the e2e fixture timed out; the fixture now nudges the client trust event to start the docks subscription (a no-op under built/preview's static RPC).Vue DevTools bridge fix
@vue/devtools-kit's iframe messaging channel only answers the iframe registered viasetIframeServerContext(), and that call lived in the legacygetIframe()path — dead now that the panel renders as an iframe inside the Vite DevTools dock. The host Vue DevTools backend therefore never learned which iframe to talk to. The host client now binds the dock iframe viasetIframeServerContext()as soon as Vite DevTools mounts it. (This also fixes thetab-piniae2e spec, which was flaky/failing onmainbefore this PR.)Verification
pnpm lint,pnpm build,pnpm typecheckall pass.pnpm test:e2e(dev + built) passes locally and in CI — dev 44 passed, built 3 passed, 0 failures (thetab-piniaspec that failed onmainnow passes reliably, ~6s vs the previous 30s timeout).This PR was created with the help of an agent.