Skip to content

Commit ad8f305

Browse files
authored
feat: use webcomponents for embedded views (#864)
1 parent 44a3947 commit ad8f305

File tree

28 files changed

+1455
-971
lines changed

28 files changed

+1455
-971
lines changed

eslint.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ export default antfu(
66
formatters: true,
77
unocss: true,
88
pnpm: true,
9+
ignore: [
10+
'**/.generated/**',
11+
],
912
},
1013
{
1114
rules: {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"type": "module",
44
"version": "2.4.1",
55
"private": true,
6-
"packageManager": "[email protected].0",
6+
"packageManager": "[email protected].1",
77
"repository": {
88
"type": "git",
99
"url": "git+https://github.com/nuxt/devtools.git"

packages/devtools-kit/types.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './dist/types'
1+
export type * from './dist/types.d.mts'
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { NuxtDevtoolsIframeClient } from '@nuxt/devtools-kit/types'
2+
import type { Ref } from 'vue'
13
import { useDevtoolsClient } from '@nuxt/devtools-kit/iframe-client'
24

3-
export const devToolsClient = useDevtoolsClient()
5+
export const devToolsClient: Ref<NuxtDevtoolsIframeClient | undefined> = useDevtoolsClient()

packages/devtools/build.config.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,43 @@
11
import { defineBuildConfig } from 'unbuild'
2+
import Vue from 'unplugin-vue/rollup'
3+
import { buildCSS } from './src/webcomponents/scripts/build-css'
24

35
export default defineBuildConfig({
46
entries: [
57
'src/module',
68
// Chunking
79
'src/types',
810
'src/dirs',
11+
'src/webcomponents/index',
912
],
1013
externals: [
1114
'nuxt',
1215
'nuxt/schema',
1316
'vite',
1417
'@nuxt/kit',
1518
'@nuxt/schema',
19+
'@nuxt/devtools',
20+
'@nuxt/devtools/webcomponents',
1621
// Type only
1722
'vue',
1823
'vue-router',
1924
'unstorage',
2025
'nitropack',
26+
'vite-plugin-vue-tracer',
2127
],
2228
rollup: {
2329
inlineDependencies: true,
2430
},
31+
hooks: {
32+
'build:before': async (ctx) => {
33+
if (ctx.options.stub)
34+
return
35+
await buildCSS()
36+
},
37+
'rollup:options': function (ctx, options) {
38+
if (ctx.options.stub)
39+
return
40+
options.plugins.push(Vue())
41+
},
42+
},
2543
})

packages/devtools/client/composables/editor.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ export function useOpenInEditor() {
1212
const router = useRouter()
1313
const virtualFileId = useCurrentVirtualFile()
1414

15-
return async (filepath: string) => {
15+
return async (filepath?: string) => {
16+
if (!filepath)
17+
return
18+
1619
const buildDir = config.value?.buildDir
1720
const path = (buildDir && filepath.startsWith(buildDir))
1821
? `#build${filepath.slice(buildDir.length)}`

packages/devtools/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"types": "./dist/module.d.mts",
1616
"import": "./dist/module.mjs"
1717
},
18+
"./webcomponents": {
19+
"types": "./dist/webcomponents/index.d.mts",
20+
"import": "./dist/webcomponents/index.mjs"
21+
},
1822
"./types": {
1923
"types": "./dist/types.d.mts"
2024
},
@@ -85,6 +89,7 @@
8589
"@iconify-json/bxl": "catalog:icons",
8690
"@iconify-json/carbon": "catalog:icons",
8791
"@iconify-json/logos": "catalog:icons",
92+
"@iconify-json/ph": "catalog:icons",
8893
"@iconify-json/ri": "catalog:icons",
8994
"@iconify-json/simple-icons": "catalog:icons",
9095
"@iconify-json/tabler": "catalog:icons",
@@ -103,9 +108,11 @@
103108
"@xterm/addon-fit": "catalog:frontend",
104109
"@xterm/xterm": "catalog:frontend",
105110
"cronstrue": "catalog:frontend",
111+
"exsolve": "catalog:buildtools",
106112
"floating-vue": "catalog:frontend",
107113
"fuse.js": "catalog:frontend",
108114
"json-editor-vue": "catalog:frontend",
115+
"lightningcss": "catalog:buildtools",
109116
"markdown-it": "catalog:frontend",
110117
"markdown-it-link-attributes": "catalog:frontend",
111118
"my-ua-parser": "catalog:frontend",
@@ -120,6 +127,7 @@
120127
"tsx": "catalog:cli",
121128
"unimport": "catalog:types",
122129
"unocss": "catalog:buildtools",
130+
"unplugin-vue": "catalog:buildtools",
123131
"unplugin-vue-markdown": "catalog:buildtools",
124132
"vanilla-jsoneditor": "catalog:frontend",
125133
"vis-data": "catalog:frontend",

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

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import type { NuxtDevtoolsHostClient, TimelineEventRoute, TimelineMetrics } from '@nuxt/devtools/types'
2+
import type { NuxtDevToolsInspectorProps } from '@nuxt/devtools/webcomponents'
23
import type { $Fetch } from 'ofetch'
34
import type { Ref } from 'vue'
4-
import type { Router } from 'vue-router'
55

6+
import type { Router } from 'vue-router'
67
// eslint-disable-next-line ts/ban-ts-comment
78
// @ts-ignore tsconfig
89
import { useAppConfig, useRuntimeConfig } from '#imports'
10+
import { NuxtDevtoolsFrame, NuxtDevtoolsInspectPanel } from '@nuxt/devtools/webcomponents'
911
import { setIframeServerContext } from '@vue/devtools-kit'
12+
1013
import { createHooks } from 'hookable'
1114
import { debounce } from 'perfect-debounce'
12-
1315
import { events as inspectorEvents, hasData as inspectorHasData, state as inspectorState } from 'vite-plugin-vue-tracer/client/overlay'
14-
import { computed, createApp, h, markRaw, ref, shallowReactive, shallowRef, toRef, watch } from 'vue'
15-
import { initTimelineMetrics } from '../../function-metrics-helpers'
16-
import Main from './Main.vue'
16+
import { computed, markRaw, reactive, ref, shallowReactive, shallowRef, toRef, watch } from 'vue'
1717

18+
import { initTimelineMetrics } from '../../function-metrics-helpers'
19+
import { settings } from '../../settings'
1820
import { popupWindow, state } from './state'
1921

2022
const clientRef = shallowRef<NuxtDevtoolsHostClient>()
@@ -34,6 +36,9 @@ export async function setupDevToolsClient({
3436
timeMetric: any
3537
router: Router
3638
}) {
39+
let iframe: HTMLIFrameElement | undefined
40+
let inspector: NuxtDevtoolsHostClient['inspector'] | undefined
41+
3742
const colorMode = useClientColorMode()
3843
const timeline = initTimelineMetrics()
3944

@@ -108,8 +113,6 @@ export async function setupDevToolsClient({
108113

109114
window.__NUXT_DEVTOOLS_HOST__ = client
110115

111-
let iframe: HTMLIFrameElement | undefined
112-
113116
function syncClient() {
114117
if (!client.inspector)
115118
client.inspector = getInspectorInstance()
@@ -183,33 +186,65 @@ export async function setupDevToolsClient({
183186
}
184187

185188
function getInspectorInstance(): NuxtDevtoolsHostClient['inspector'] {
186-
const isAvailable = ref(inspectorHasData())
189+
if (inspector)
190+
return inspector
187191

188-
if (!inspectorEvents.events.disabled?.length) {
189-
inspectorEvents.on('disabled', () => {
190-
inspectorState.isVisible = false
191-
client?.hooks.callHook('host:inspector:close')
192-
})
193-
}
194-
if (!inspectorEvents.events.enabled?.length) {
195-
inspectorEvents.on('enabled', () => {
196-
inspectorState.isVisible = true
197-
})
198-
}
199-
if (!inspectorEvents.events.click?.length) {
200-
inspectorEvents.on('click', async (info) => {
201-
inspectorState.isEnabled = false
202-
await client.hooks.callHook('host:inspector:click', info.fullpath)
203-
})
204-
}
192+
const props = reactive<NuxtDevToolsInspectorProps>({
193+
mouse: { x: 0, y: 0 },
194+
matched: undefined,
195+
})
205196

197+
const component = new NuxtDevtoolsInspectPanel(reactive({ props }))
198+
document.body.appendChild(component)
199+
Object.assign(component.style, {
200+
zIndex: 999999,
201+
position: 'fixed',
202+
})
203+
component.addEventListener('close', () => {
204+
props.matched = undefined
205+
inspectorState.isEnabled = false
206+
})
207+
component.addEventListener('selectParent', () => {
208+
const parent = inspectorState.main?.getParent()
209+
if (parent) {
210+
inspectorState.main = parent
211+
props.matched = parent
212+
}
213+
})
214+
// eslint-disable-next-line ts/ban-ts-comment
215+
// @ts-ignore WebComponent types
216+
component.addEventListener('openInEditor', (e) => {
217+
const url = (e as any)?.detail?.[0]
218+
if (url)
219+
client.hooks.callHook('host:inspector:click', url)
220+
})
221+
222+
inspectorEvents.on('hover', () => {
223+
inspectorState.isFocused = false
224+
})
225+
inspectorEvents.on('disabled', () => {
226+
inspectorState.isVisible = false
227+
client?.hooks.callHook('host:inspector:close')
228+
})
229+
inspectorEvents.on('enabled', () => {
230+
inspectorState.isVisible = true
231+
})
232+
inspectorEvents.on('click', async (info, e) => {
233+
inspectorState.isFocused = true
234+
inspectorState.isVisible = true
235+
236+
props.matched = info
237+
props.mouse = { x: e.clientX, y: e.clientY }
238+
})
239+
240+
const isAvailable = ref(inspectorHasData())
206241
if (!isAvailable.value) {
207242
inspectorEvents.on('hover', async () => {
208243
isAvailable.value = inspectorHasData()
209244
})
210245
}
211246

212-
return markRaw({
247+
return inspector = markRaw({
213248
isAvailable,
214249
isEnabled: toRef(inspectorState, 'isEnabled'),
215250
enable: () => {
@@ -284,13 +319,13 @@ export async function setupDevToolsClient({
284319
client.devtools.toggle()
285320
})
286321

287-
const app = createApp({
288-
render: () => h(Main, { client }),
289-
devtools: {
290-
hide: true,
291-
},
292-
})
293-
app.mount(holder)
322+
const frame = new NuxtDevtoolsFrame(reactive({
323+
client,
324+
settings,
325+
state,
326+
popupWindow,
327+
}))
328+
holder.appendChild(frame)
294329
}
295330

296331
export function useClientColorMode(): Ref<ColorScheme> {

packages/devtools/src/runtime/plugins/view/state.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ import type { DevToolsFrameState } from '@nuxt/devtools/types'
22
import { shallowRef } from 'vue'
33
import { useObjectStorage } from './utils'
44

5-
export const PANEL_PADDING = 10
6-
export const PANEL_MIN = 20
7-
export const PANEL_MAX = 100
8-
95
export const popupWindow = shallowRef<Window | null>(null)
106

117
export const state = useObjectStorage<DevToolsFrameState>('nuxt-devtools-frame-state', {

0 commit comments

Comments
 (0)