Skip to content

Commit 827a170

Browse files
committed
feat: reactive dock entries
1 parent 30780b7 commit 827a170

File tree

14 files changed

+118
-59
lines changed

14 files changed

+118
-59
lines changed

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
"nanoevents": "catalog:deps",
6666
"open": "catalog:deps",
6767
"pathe": "catalog:deps",
68+
"perfect-debounce": "catalog:deps",
6869
"sirv": "catalog:deps",
6970
"ws": "catalog:deps"
7071
},

packages/core/playground/vite.config.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,32 @@ export default defineConfig({
8484
title: 'Custom',
8585
icon: 'ph:newspaper-clipping-duotone',
8686
})
87+
88+
ctx.docks.register({
89+
id: 'counter',
90+
type: 'action',
91+
icon: 'material-symbols:counter-1',
92+
title: 'Counter',
93+
// TODO: HMR
94+
action: ctx.utils.createSimpleClientScript(() => {}),
95+
})
96+
97+
let count = 1
98+
// eslint-disable-next-line unimport/auto-insert
99+
setInterval(() => {
100+
count = (count + 1) % 5
101+
ctx.docks.update({
102+
id: 'counter',
103+
type: 'action',
104+
icon: `material-symbols:counter-${count}`,
105+
title: `Counter ${count}`,
106+
// TODO: HMR
107+
action: ctx.utils.createSimpleClientScript(() => {
108+
// eslint-disable-next-line no-alert
109+
alert(`Counter ${count}`)
110+
}),
111+
})
112+
}, 1000)
87113
},
88114
},
89115
},

packages/core/src/client/webcomponents/state/dock.ts

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { DevToolsDockEntry } from '@vitejs/devtools-kit'
22
import type { ClientRpcReturn, DockEntryState, DockEntryStateEvents, DockPanelStorage, DocksContext } from '@vitejs/devtools-kit/client'
3-
import type { Ref } from 'vue'
3+
import type { Ref, ShallowRef } from 'vue'
44
import { createNanoEvents } from 'nanoevents'
5-
import { computed, markRaw, reactive, ref, shallowRef, watch } from 'vue'
5+
import { computed, markRaw, reactive, ref, shallowRef, watch, watchEffect } from 'vue'
66

77
export function DEFAULT_DOCK_PANEL_STORE(): DockPanelStorage {
88
return {
@@ -52,28 +52,56 @@ function createDockEntryState(
5252
return state
5353
}
5454

55+
let _docksEntriesRef: ShallowRef<DevToolsDockEntry[]> | undefined
56+
export async function useDocksEntries(rpcReturn: ClientRpcReturn): Promise<Ref<DevToolsDockEntry[]>> {
57+
if (_docksEntriesRef) {
58+
return _docksEntriesRef
59+
}
60+
const dockEntries = _docksEntriesRef = shallowRef<DevToolsDockEntry[]>([])
61+
async function updateDocksEntries() {
62+
dockEntries.value = (await rpcReturn.rpc.$call('vite:core:list-dock-entries')).map(entry => Object.freeze(entry))
63+
// eslint-disable-next-line no-console
64+
console.log('[VITE DEVTOOLS] Docks Entries Updated', [...dockEntries.value])
65+
}
66+
rpcReturn.clientRpc.register({
67+
name: 'vite:core:list-dock-entries:updated',
68+
type: 'action',
69+
handler: () => updateDocksEntries(),
70+
})
71+
await updateDocksEntries()
72+
return dockEntries
73+
}
74+
75+
let _docksContext: DocksContext | undefined
5576
export async function createDocksContext(
5677
clientType: 'embedded' | 'standalone',
5778
rpcReturn: ClientRpcReturn,
5879
panelStore?: Ref<DockPanelStorage>,
5980
): Promise<DocksContext> {
81+
if (_docksContext) {
82+
return _docksContext
83+
}
84+
6085
const selected = ref<DevToolsDockEntry | null>(null)
61-
const dockEntries = shallowRef((await rpcReturn.rpc.$call('vite:core:list-dock-entries')).map(entry => Object.freeze(entry)))
62-
// eslint-disable-next-line no-console
63-
console.log('[VITE DEVTOOLS] Docks Entries', [...dockEntries.value])
64-
// TODO: get board case from rpc when entries updates
86+
const dockEntries = await useDocksEntries(rpcReturn)
87+
6588
const dockEntryStateMap: Map<string, DockEntryState> = reactive(new Map())
66-
for (const entry of dockEntries.value) {
67-
// TODO: handle update
68-
dockEntryStateMap.set(
69-
entry.id,
70-
createDockEntryState(entry, selected),
71-
)
72-
}
89+
watchEffect(() => {
90+
for (const entry of dockEntries.value) {
91+
if (dockEntryStateMap.has(entry.id)) {
92+
dockEntryStateMap.get(entry.id)!.entryMeta = entry
93+
continue
94+
}
95+
dockEntryStateMap.set(
96+
entry.id,
97+
createDockEntryState(entry, selected),
98+
)
99+
}
100+
})
73101

74102
panelStore ||= ref(DEFAULT_DOCK_PANEL_STORE())
75103

76-
return reactive({
104+
_docksContext = reactive({
77105
panel: {
78106
store: panelStore,
79107
isDragging: false,
@@ -82,7 +110,7 @@ export async function createDocksContext(
82110
},
83111
docks: {
84112
selected,
85-
entries: dockEntries.value,
113+
entries: dockEntries,
86114
entryToStateMap: markRaw(dockEntryStateMap),
87115
getStateById: (id: string) => dockEntryStateMap.get(id),
88116
switchEntry: async (id: string | null) => {
@@ -102,4 +130,6 @@ export async function createDocksContext(
102130
clientRpc: rpcReturn.clientRpc,
103131
clientType,
104132
})
133+
134+
return _docksContext
105135
}
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
import type { DevToolsDockEntry, DevToolsDockHost as DevToolsDockHostType, DevToolsNodeContext } from '@vitejs/devtools-kit'
2+
import { debounce } from 'perfect-debounce'
23

34
export class DevToolsDockHost implements DevToolsDockHostType {
45
public readonly views: Map<string, DevToolsDockEntry> = new Map()
6+
private _sendOnChange: (() => void)
57

68
constructor(
79
public readonly context: DevToolsNodeContext,
810
) {
11+
this._sendOnChange = debounce(() => {
12+
context.rpc.boardcast?.$callOptional('vite:core:list-dock-entries:updated')
13+
}, 10)
914
}
1015

1116
values(): DevToolsDockEntry[] {
1217
return Array.from(this.views.values())
1318
}
1419

15-
register(view: DevToolsDockEntry): void {
16-
if (this.views.has(view.id)) {
20+
register(view: DevToolsDockEntry, force?: boolean): void {
21+
if (this.views.has(view.id) && !force) {
1722
throw new Error(`Dock with id "${view.id}" is already registered`)
1823
}
1924
this.views.set(view.id, view)
25+
this._sendOnChange()
2026
}
2127

2228
update(view: DevToolsDockEntry): void {
2329
if (!this.views.has(view.id)) {
2430
throw new Error(`Dock with id "${view.id}" is not registered. Use register() to add new docks.`)
2531
}
2632
this.views.set(view.id, view)
33+
this._sendOnChange()
2734
}
2835
}

packages/core/src/node/host-functions.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import type { DevToolsNodeContext, DevToolsRpcServerFunctions } from '@vitejs/devtools-kit'
1+
import type { DevToolsNodeContext, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from '@vitejs/devtools-kit'
2+
import type { BirpcGroup } from 'birpc'
23
import { RpcFunctionsCollectorBase } from 'birpc-x'
34

45
export class RpcFunctionsHost extends RpcFunctionsCollectorBase<DevToolsRpcServerFunctions, DevToolsNodeContext> {
6+
boardcast: BirpcGroup<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions>['broadcast'] = undefined!
7+
58
constructor(
69
context: DevToolsNodeContext,
710
) {

packages/core/src/node/rpc/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ export type ServerFunctionsDump = {
2323

2424
declare module '@vitejs/devtools-kit' {
2525
export interface DevToolsRpcServerFunctions extends ServerFunctions {}
26+
27+
export interface DevToolsRpcClientFunctions {
28+
'vite:core:list-dock-entries:updated': () => Promise<void>
29+
}
2630
}

packages/core/src/node/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { createWsServer } from './ws'
77
export async function createDevToolsMiddleware(options: CreateWsServerOptions) {
88
const app = createApp()
99

10-
const { rpc, getMetadata } = await createWsServer(options)
10+
const { rpc, getConnectionMeta: getMetadata } = await createWsServer(options)
1111

1212
app.use('/.vdt-connection.json', eventHandler(async (event) => {
1313
event.node.res.setHeader('Content-Type', 'application/json')

packages/core/src/node/ws.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-console */
2-
import type { ConnectionMeta, DevToolsNodeContext } from '@vitejs/devtools-kit'
2+
import type { ConnectionMeta, DevToolsNodeContext, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from '@vitejs/devtools-kit'
33
import type { WebSocket } from 'ws'
44
import { createRpcServer } from '@vitejs/devtools-rpc'
55
import { createWsRpcPreset } from '@vitejs/devtools-rpc/presets/ws/server'
@@ -32,7 +32,7 @@ export async function createWsServer(options: CreateWsServerOptions) {
3232
},
3333
})
3434

35-
const rpc = createRpcServer<any, any>(
35+
const rpc = createRpcServer<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions>(
3636
rpcHost.functions,
3737
{
3838
preset,
@@ -46,7 +46,9 @@ export async function createWsServer(options: CreateWsServerOptions) {
4646
},
4747
)
4848

49-
const getMetadata = async (): Promise<ConnectionMeta> => {
49+
rpcHost.boardcast = rpc.broadcast
50+
51+
const getConnectionMeta = async (): Promise<ConnectionMeta> => {
5052
return {
5153
backend: 'websocket',
5254
websocket: port,
@@ -56,7 +58,7 @@ export async function createWsServer(options: CreateWsServerOptions) {
5658
return {
5759
port,
5860
rpc,
59-
functions: rpcHost,
60-
getMetadata,
61+
rpcHost,
62+
getConnectionMeta,
6163
}
6264
}

packages/kit/src/types/rpc.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import type { BirpcGroup } from 'birpc'
12
import type { RpcFunctionsCollectorBase } from 'birpc-x'
2-
import type { DevToolsRpcServerFunctions } from './rpc-augments'
3+
import type { DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from './rpc-augments'
34
import type { DevToolsNodeContext } from './vite-plugin'
45

5-
export type RpcFunctionsHost = RpcFunctionsCollectorBase<DevToolsRpcServerFunctions, DevToolsNodeContext>
6+
export type RpcFunctionsHost = RpcFunctionsCollectorBase<DevToolsRpcServerFunctions, DevToolsNodeContext> & {
7+
boardcast: BirpcGroup<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions>['broadcast']
8+
}

packages/vite/src/app/state/data.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)