Skip to content

Commit 93d2a33

Browse files
committed
chore: update
1 parent 10a4d8e commit 93d2a33

File tree

8 files changed

+105
-9
lines changed

8 files changed

+105
-9
lines changed

docs/kit/index.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ DevTools Kit offers a complete toolkit for building DevTools integrations:
1919

2020
- **🔌 [Built-in RPC Layer](#remote-procedure-calls-rpc)**: Type-safe bidirectional communication between your Node.js server and browser clients, eliminating the need to set up WebSocket connections or message passing manually
2121

22+
- **🔗 [Shared State](#shared-state)**: Share data between server and client with automatic synchronization
23+
2224
- **🌐 Isomorphic Views Hosting**: Write your UI once and deploy it anywhere—as embedded floating panels, browser extension panels, standalone webpages, or even deployable SPAs for sharing build snapshots (work in progress).
2325

2426
## Why DevTools Kit?
@@ -418,6 +420,89 @@ rpc.client.register({
418420
})
419421
```
420422

423+
### Shared State
424+
425+
The DevTools Kit provides a built-in shared state system that enables you to share data between the server and client with automatic synchronization.
426+
427+
On the server side, you can get the shared state using `ctx.rpc.sharedState.get(name, options)`:
428+
429+
```ts {6-10}
430+
export default function myPlugin(): Plugin {
431+
return {
432+
name: 'my-plugin',
433+
devtools: {
434+
async setup(ctx) {
435+
// Get the shared state
436+
const state = await ctx.rpc.sharedState.get('my-plugin:state', {
437+
initialValue: {
438+
count: 0,
439+
name: 'John Doe',
440+
},
441+
})
442+
443+
// Use .value() to get the current state
444+
console.log(state.value()) // { count: 0, name: 'John Doe' }
445+
446+
setTimeout(() => {
447+
// Mutate the shared state, changes will be automatically synchronized to all the connected clients
448+
state.mutate((state) => {
449+
state.count += 1
450+
})
451+
}, 1000)
452+
},
453+
},
454+
}
455+
}
456+
```
457+
458+
<details>
459+
<summary>Type-safe shared state</summary>
460+
461+
The shared state is type-safe, you can get the state with the type of the initial value. To do so, you need to extend the `DevToolsRpcSharedStates` interface in your plugin's type definitions.
462+
463+
```ts [src/types.ts]
464+
import '@vitejs/devtools-kit'
465+
466+
declare module '@vitejs/devtools-kit' {
467+
interface DevToolsRpcSharedStates {
468+
'my-plugin:state': { count: number, name: string }
469+
}
470+
}
471+
```
472+
473+
</details>
474+
475+
On the client side, you can get the shared state using `client.rpc.sharedState.get(name)`:
476+
477+
```ts {6-10}
478+
import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
479+
480+
const client = await getDevToolsRpcClient()
481+
482+
const state = await client.rpc.sharedState.get('my-plugin:state')
483+
484+
console.log(state.value()) // { count: 0, name: 'John Doe' }
485+
486+
// Use .on('updated') to subscribe to changes
487+
state.on('updated', (newState) => {
488+
console.log(newState) // { count: 1, name: 'John Doe' }
489+
})
490+
```
491+
492+
For example, if you use Vue, you can wrap it into a reactive ref:
493+
494+
```ts {6-10}
495+
import { shallowRef } from 'vue'
496+
497+
const sharedState = await client.rpc.sharedState.get('my-plugin:state')
498+
const state = shallowRef(sharedState.value())
499+
sharedState.on('updated', (newState) => {
500+
state.value = newState
501+
})
502+
503+
// Now the `state` ref will be updated automatically when the shared state changes
504+
```
505+
421506
## References
422507

423508
The docs might not cover all the details, please help us to improve it by submitting PRs. And in the meantime, you can refer to the following existing DevTools integrations for reference (but note they might not always be up to date with the latest API changes):

packages/core/playground/src/pages/devtools.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ onMounted(async () => {
1515
isTrustedRef.value = isTrusted
1616
})
1717
18-
const state = await client.sharedState.get<{ count: number }>('counter')
18+
const state = await client.sharedState.get('counter')
1919
2020
increment = () => {
2121
state.mutate((state) => {

packages/core/playground/vite.config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import { DevToolsViteUI } from '../../vite/src/node'
1111
import { DevTools } from '../src'
1212
import { buildCSS } from '../src/client/webcomponents/scripts/build-css'
1313

14+
declare module '@vitejs/devtools-kit' {
15+
interface DevToolsRpcSharedStates {
16+
counter: { count: number }
17+
}
18+
}
19+
1420
// https://vite.dev/config/
1521
export default defineConfig({
1622
define: {

packages/core/src/node/rpc/internal/state/get.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DevToolsNodeContext } from '@vitejs/devtools-kit'
1+
import type { DevToolsNodeContext, DevToolsRpcSharedStates } from '@vitejs/devtools-kit'
22
import { defineRpcFunction } from '@vitejs/devtools-kit'
33

44
export const sharedStateGet = defineRpcFunction({
@@ -7,7 +7,7 @@ export const sharedStateGet = defineRpcFunction({
77
setup: (context: DevToolsNodeContext) => {
88
return {
99
handler: async (key: string) => {
10-
const state = await context.rpc.sharedState.get(key)
10+
const state = await context.rpc.sharedState.get(key as keyof DevToolsRpcSharedStates)
1111
return state.value()
1212
},
1313
}

packages/core/src/node/rpc/internal/state/patch.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DevToolsNodeContext } from '@vitejs/devtools-kit'
1+
import type { DevToolsNodeContext, DevToolsRpcSharedStates } from '@vitejs/devtools-kit'
22
import type { SharedStatePatch } from '@vitejs/devtools-kit/utils/shared-state'
33
import { defineRpcFunction } from '@vitejs/devtools-kit'
44

@@ -8,7 +8,7 @@ export const sharedStatePatch = defineRpcFunction({
88
setup: (context: DevToolsNodeContext) => {
99
return {
1010
handler: async (key: string, patches: SharedStatePatch[], syncId: string) => {
11-
const state = await context.rpc.sharedState.get(key)
11+
const state = await context.rpc.sharedState.get(key as keyof DevToolsRpcSharedStates)
1212
state.patch(patches, syncId)
1313
},
1414
}

packages/core/src/node/rpc/internal/state/set.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { DevToolsNodeContext } from '@vitejs/devtools-kit'
1+
import type { DevToolsNodeContext, DevToolsRpcSharedStates } from '@vitejs/devtools-kit'
22
import { defineRpcFunction } from '@vitejs/devtools-kit'
33

44
export const sharedStateSet = defineRpcFunction({
@@ -7,7 +7,7 @@ export const sharedStateSet = defineRpcFunction({
77
setup: (context: DevToolsNodeContext) => {
88
return {
99
handler: async (key: string, value: any, syncId: string) => {
10-
const state = await context.rpc.sharedState.get(key)
10+
const state = await context.rpc.sharedState.get(key as keyof DevToolsRpcSharedStates)
1111
state.mutate(() => value, syncId)
1212
},
1313
}

packages/kit/src/types/rpc-augments.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ export interface DevToolsRpcClientFunctions {}
77
* To be extended
88
*/
99
export interface DevToolsRpcServerFunctions {}
10+
11+
/**
12+
* To be extended
13+
*/
14+
export interface DevToolsRpcSharedStates {}

packages/kit/src/types/rpc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { DevToolsNodeRpcSessionMeta } from '@vitejs/devtools-rpc/presets/ws
22
import type { BirpcReturn } from 'birpc'
33
import type { RpcFunctionsCollectorBase } from 'birpc-x'
44
import type { SharedState } from '../utils/shared-state'
5-
import type { DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from './rpc-augments'
5+
import type { DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, DevToolsRpcSharedStates } from './rpc-augments'
66
import type { DevToolsNodeContext } from './vite-plugin'
77

88
export type { DevToolsNodeRpcSessionMeta }
@@ -49,5 +49,5 @@ export interface RpcSharedStateGetOptions<T> {
4949
}
5050

5151
export interface RpcSharedStateHost {
52-
get: <T extends object>(key: string, options?: RpcSharedStateGetOptions<T>) => Promise<SharedState<T>>
52+
get: <T extends keyof DevToolsRpcSharedStates>(key: T, options?: RpcSharedStateGetOptions<DevToolsRpcSharedStates[T]>) => Promise<SharedState<DevToolsRpcSharedStates[T]>>
5353
}

0 commit comments

Comments
 (0)