Skip to content

Commit 7dac16d

Browse files
authored
fix: resolve devtools client runtime errors (#1075)
1 parent 30541d9 commit 7dac16d

12 files changed

Lines changed: 104 additions & 43 deletions

File tree

‎packages/devtools/build.config.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import { writeFile } from 'node:fs/promises'
12
import { defineBuildConfig } from 'unbuild'
23
import Vue from 'unplugin-vue/rollup'
34
import { buildCSS } from './src/webcomponents/scripts/build-css'
45

6+
const WEB_COMPONENTS_STUB = new URL('./dist/webcomponents/index.mjs', import.meta.url)
7+
58
export default defineBuildConfig({
69
entries: [
710
'src/module',
@@ -39,5 +42,16 @@ export default defineBuildConfig({
3942
return
4043
options.plugins.push(Vue())
4144
},
45+
'build:done': async (ctx) => {
46+
if (!ctx.options.stub)
47+
return
48+
49+
// unbuild's default stub loads TypeScript through jiti. This entry is
50+
// imported by the browser-side inspector plugin, where that Node-only
51+
// loader cannot run. Vite can transform the source entry directly while
52+
// developing this workspace; published builds still receive the bundled
53+
// web component above.
54+
await writeFile(WEB_COMPONENTS_STUB, `export * from '../../src/webcomponents/index.ts'\n`)
55+
},
4256
},
4357
})

‎packages/devtools/client/app.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ registerCommands(() => [
152152
Connecting....
153153
</NLoading>
154154
<div
155-
v-else
155+
v-show="!waiting"
156156
id="nuxt-devtools-app"
157157
class="grid grid-cols-[1fr]"
158158
h-full h-screen of-hidden rounded-xl bg-base font-sans

‎packages/devtools/client/composables/npm.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export function usePackageUpdate(name: string, options?: NpmCommandOptions): Ret
1717
}
1818

1919
export function useNuxtVersion() {
20-
return useAsyncState('npm:check:nuxt', () => rpc.checkForUpdateFor('nuxt'))
20+
return usePackageUpdate('nuxt').info
2121
}
2222

2323
export function satisfyNuxtVersion(range: string) {

‎packages/devtools/client/nuxt.config.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ export default defineNuxtConfig({
102102

103103
vite: {
104104
warmupEntry: false,
105+
vue: {
106+
// floating-vue still implements its poppers with Options API mixins,
107+
// computed properties, and methods. Keep that runtime enabled even when
108+
// Nuxt's application defaults change.
109+
features: {
110+
optionsAPI: true,
111+
},
112+
},
105113
$client: {
106114
build: {
107115
target: 'esnext',
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script setup lang="ts">
2+
import { definePageMeta } from '#imports'
3+
4+
definePageMeta({
5+
redirect: '/modules/overview',
6+
})
7+
</script>
8+
9+
<template>
10+
<div />
11+
</template>

‎packages/devtools/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
}
5555
},
5656
"dependencies": {
57+
"@devframes/hub": "catalog:prod",
5758
"@devframes/plugin-code-server": "catalog:prod",
5859
"@devframes/plugin-data-inspector": "catalog:prod",
5960
"@nuxt/devtools-kit": "workspace:*",

‎packages/devtools/src/runtime/plugins/view/client.ts‎

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import type { $Fetch } from 'ofetch'
44
import type { Ref } from 'vue'
55

66
import type { Router } from 'vue-router'
7+
import { getDevframeClientContext } from '@devframes/hub/client'
78
import { NuxtDevtoolsInspectPanel } from '@nuxt/devtools/webcomponents'
8-
import { getDevToolsClientContext } from '@vitejs/devtools-kit/client'
99

1010
import { createHooks } from 'hookable'
1111
import { debounce } from 'perfect-debounce'
@@ -17,14 +17,14 @@ import { useAppConfig } from '#imports'
1717

1818
import { initTimelineMetrics } from '../../function-metrics-helpers'
1919

20-
// The `Nuxt` dock group id (see `NUXT_DEVTOOLS_GROUP_ID`). Activating the group
21-
// auto-opens its `defaultChildId` (the shared-frame anchor). The anchor iframe
22-
// dock (`nuxt:devtools`) hosts the one kept-alive client iframe that all tab
23-
// members soft-navigate within.
24-
const NUXT_DOCK_GROUP_ID = 'nuxt'
20+
// Host controls must update the visible Devframe viewer context, rather than
21+
// Vite's separate dock-registration context. Target the shared-frame anchor
22+
// explicitly so open/navigate always mounts the one kept-alive client iframe
23+
// used by every Nuxt tab.
24+
const NUXT_DOCK_ANCHOR_ID = 'nuxt:devtools'
2525

26-
function getViteDevToolsContext() {
27-
return getDevToolsClientContext() as any
26+
function getDevframeContext() {
27+
return getDevframeClientContext() as any
2828
}
2929

3030
const clientRef = shallowRef<NuxtDevtoolsHostClient>()
@@ -56,27 +56,27 @@ export async function setupDevToolsClient({
5656

5757
devtools: {
5858
toggle() {
59-
const ctx = getViteDevToolsContext()
59+
const ctx = getDevframeContext()
6060
if (ctx)
61-
ctx.docks.toggleEntry(NUXT_DOCK_GROUP_ID)
61+
ctx.docks.toggleEntry(NUXT_DOCK_ANCHOR_ID)
6262
},
6363
close() {
64-
const ctx = getViteDevToolsContext()
64+
const ctx = getDevframeContext()
6565
if (ctx)
66-
ctx.panel.store.open = false
66+
ctx.panel.session.open = false
6767
},
6868
open() {
69-
const ctx = getViteDevToolsContext()
69+
const ctx = getDevframeContext()
7070
if (ctx) {
71-
ctx.panel.store.open = true
72-
ctx.docks.switchEntry(NUXT_DOCK_GROUP_ID)
71+
ctx.panel.session.open = true
72+
ctx.docks.switchEntry(NUXT_DOCK_ANCHOR_ID)
7373
}
7474
},
7575
async navigate(path: string) {
76-
const ctx = getViteDevToolsContext()
76+
const ctx = getDevframeContext()
7777
if (ctx) {
78-
ctx.panel.store.open = true
79-
ctx.docks.switchEntry(NUXT_DOCK_GROUP_ID)
78+
ctx.panel.session.open = true
79+
ctx.docks.switchEntry(NUXT_DOCK_ANCHOR_ID)
8080
}
8181
await client.hooks.callHook('host:action:navigate', path)
8282
},

‎pnpm-lock.yaml‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pnpm-workspace.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ catalogs:
199199
inlined:
200200
package-manager-detector: ^1.8.0
201201
prod:
202+
'@devframes/hub': *devframe
202203
'@devframes/plugin-code-server': *devframe
203204
'@devframes/plugin-data-inspector': *devframe
204205
'@nuxt/kit': *nuxt-kit

‎tests/e2e/fixtures/devtools.ts‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ interface DevToolsFixtures {
1717
}
1818

1919
// e2e servers run with `VITE_DEVTOOLS_DISABLE_CLIENT_AUTH=true`, which trusts the
20-
// *server* peer (so RPC is allowed) but never flips the *client-side* trust flag.
21-
// Until it does, Vite DevTools never subscribes to the dock list, so no dock —
22-
// and therefore no Nuxt group — ever appears. Nudge the flag here. This is purely
23-
// test-environment plumbing; it is not something the tests assert on.
20+
// *server* peer (so RPC is allowed), but the client can still initialize before
21+
// that state is reflected locally. Complete the handshake through Devframe's
22+
// public API before waiting for docks. This is purely test-environment plumbing;
23+
// it is not something the tests assert on.
2424
async function ensureDockReady(page: Page): Promise<void> {
2525
await page.waitForFunction(
2626
() => Boolean((globalThis as any).__NUXT_DEVTOOLS_HOST__?.devtools),
@@ -32,11 +32,16 @@ async function ensureDockReady(page: Page): Promise<void> {
3232
null,
3333
{ timeout: 30_000 },
3434
)
35-
await page.evaluate(() => {
36-
const ctx = (globalThis as any).__DEVFRAME_HUB_CLIENT_CONTEXT__
37-
if (ctx?.rpc && !ctx.rpc.isTrusted)
38-
ctx.rpc.events?.emit?.('rpc:is-trusted:updated', true)
35+
await page.evaluate(async () => {
36+
const rpc = (globalThis as any).__DEVFRAME_HUB_CLIENT_CONTEXT__?.rpc
37+
if (rpc && !rpc.isTrusted)
38+
await rpc.requestTrust()
3939
})
40+
await page.waitForFunction(
41+
() => Boolean((globalThis as any).__DEVFRAME_HUB_CLIENT_CONTEXT__?.rpc?.isTrusted),
42+
null,
43+
{ timeout: 30_000 },
44+
)
4045
await page.waitForFunction(
4146
() => Boolean((globalThis as any).__DEVFRAME_HUB_CLIENT_CONTEXT__?.docks?.entries?.length),
4247
null,

0 commit comments

Comments
 (0)