@vitejs/devtools-kit 0.0.0-alpha.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,256 @@
1
+ # Project Structure
2
+
3
+ Recommended file organization for DevTools integrations.
4
+
5
+ ## Basic Structure
6
+
7
+ ```
8
+ my-devtools-plugin/
9
+ ├── src/
10
+ │ ├── node/
11
+ │ │ ├── index.ts # Plugin entry (exports main plugin)
12
+ │ │ ├── rpc/
13
+ │ │ │ ├── index.ts # RPC function exports
14
+ │ │ │ └── functions/ # Individual RPC functions
15
+ │ │ │ ├── get-modules.ts
16
+ │ │ │ └── get-stats.ts
17
+ │ │ └── utils.ts # Server-side utilities
18
+ │ ├── client/
19
+ │ │ ├── main.ts # Client app entry
20
+ │ │ ├── App.vue # Root component
21
+ │ │ └── composables/
22
+ │ │ └── rpc.ts # RPC composables
23
+ │ ├── types.ts # Type augmentations
24
+ │ └── shared/
25
+ │ └── constants.ts # Shared constants
26
+ ├── dist/
27
+ │ ├── index.mjs # Node plugin bundle
28
+ │ └── client/ # Built client assets
29
+ ├── package.json
30
+ └── tsconfig.json
31
+ ```
32
+
33
+ ## Package.json Configuration
34
+
35
+ ```json
36
+ {
37
+ "name": "my-devtools-plugin",
38
+ "type": "module",
39
+ "exports": {
40
+ ".": {
41
+ "import": "./dist/index.mjs",
42
+ "types": "./dist/index.d.ts"
43
+ },
44
+ "./devtools-action": {
45
+ "import": "./dist/devtools-action.mjs"
46
+ }
47
+ },
48
+ "files": ["dist"],
49
+ "scripts": {
50
+ "build": "tsdown src/node/index.ts && vite build src/client",
51
+ "dev": "vite src/client"
52
+ },
53
+ "dependencies": {},
54
+ "devDependencies": {
55
+ "@vitejs/devtools-kit": "^0.x.x",
56
+ "vite": "^6.x.x"
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Plugin Entry (src/node/index.ts)
62
+
63
+ ```ts
64
+ /// <reference types="@vitejs/devtools-kit" />
65
+ import type { Plugin } from 'vite'
66
+ import { fileURLToPath } from 'node:url'
67
+ import { rpcFunctions } from './rpc'
68
+ import '../types'
69
+
70
+ const clientDist = fileURLToPath(
71
+ new URL('../../dist/client', import.meta.url)
72
+ )
73
+
74
+ export default function myPlugin(): Plugin {
75
+ return {
76
+ name: 'my-plugin',
77
+
78
+ devtools: {
79
+ setup(ctx) {
80
+ // Register all RPC functions
81
+ for (const fn of rpcFunctions) {
82
+ ctx.rpc.register(fn)
83
+ }
84
+
85
+ // Host static UI
86
+ ctx.views.hostStatic('/.my-plugin/', clientDist)
87
+
88
+ // Register dock entry
89
+ ctx.docks.register({
90
+ id: 'my-plugin',
91
+ title: 'My Plugin',
92
+ icon: 'ph:puzzle-piece-duotone',
93
+ type: 'iframe',
94
+ url: '/.my-plugin/',
95
+ })
96
+ },
97
+ },
98
+ }
99
+ }
100
+ ```
101
+
102
+ ## RPC Index (src/node/rpc/index.ts)
103
+
104
+ ```ts
105
+ import type { RpcDefinitionsToFunctions } from '@vitejs/devtools-kit'
106
+ import { getModules } from './functions/get-modules'
107
+ import { getStats } from './functions/get-stats'
108
+ import '@vitejs/devtools-kit'
109
+
110
+ export const rpcFunctions = [
111
+ getModules,
112
+ getStats,
113
+ ] as const
114
+
115
+ export type ServerFunctions = RpcDefinitionsToFunctions<typeof rpcFunctions>
116
+
117
+ declare module '@vitejs/devtools-kit' {
118
+ export interface DevToolsRpcServerFunctions extends ServerFunctions {}
119
+ }
120
+ ```
121
+
122
+ ## RPC Function (src/node/rpc/functions/get-modules.ts)
123
+
124
+ ```ts
125
+ import type { Module } from '../../../types'
126
+ import { defineRpcFunction } from '@vitejs/devtools-kit'
127
+
128
+ export const getModules = defineRpcFunction({
129
+ name: 'my-plugin:get-modules',
130
+ type: 'query',
131
+ setup: (ctx) => {
132
+ return {
133
+ handler: async (): Promise<Module[]> => {
134
+ // Access vite config, server, etc. from ctx
135
+ const root = ctx.viteConfig.root
136
+ return []
137
+ },
138
+ }
139
+ },
140
+ })
141
+ ```
142
+
143
+ ## Type Augmentations (src/types.ts)
144
+
145
+ ```ts
146
+ import '@vitejs/devtools-kit'
147
+
148
+ export interface Module {
149
+ id: string
150
+ size: number
151
+ imports: string[]
152
+ }
153
+
154
+ export interface MyPluginState {
155
+ modules: Module[]
156
+ selectedId: string | null
157
+ }
158
+
159
+ declare module '@vitejs/devtools-kit' {
160
+ interface DevToolsRpcSharedStates {
161
+ 'my-plugin:state': MyPluginState
162
+ }
163
+ }
164
+ ```
165
+
166
+ ## Client Entry (src/client/main.ts)
167
+
168
+ ```ts
169
+ import { createApp } from 'vue'
170
+ import App from './App.vue'
171
+
172
+ createApp(App).mount('#app')
173
+ ```
174
+
175
+ ## Client RPC Composable (src/client/composables/rpc.ts)
176
+
177
+ ```ts
178
+ import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
179
+
180
+ let clientPromise: Promise<Awaited<ReturnType<typeof getDevToolsRpcClient>>>
181
+
182
+ export function useRpc() {
183
+ if (!clientPromise) {
184
+ clientPromise = getDevToolsRpcClient()
185
+ }
186
+ return clientPromise
187
+ }
188
+ ```
189
+
190
+ ## Client App Component (src/client/App.vue)
191
+
192
+ ```vue
193
+ <script setup lang="ts">
194
+ import type { Module } from '../types'
195
+ import { onMounted, shallowRef } from 'vue'
196
+ import { useRpc } from './composables/rpc'
197
+
198
+ const modules = shallowRef<Module[]>([])
199
+ const loading = shallowRef(true)
200
+
201
+ onMounted(async () => {
202
+ const rpc = await useRpc()
203
+ modules.value = await rpc.call('my-plugin:get-modules')
204
+ loading.value = false
205
+ })
206
+ </script>
207
+
208
+ <template>
209
+ <div class="p-4">
210
+ <h1 class="text-xl font-bold mb-4">
211
+ My Plugin
212
+ </h1>
213
+ <div v-if="loading">
214
+ Loading...
215
+ </div>
216
+ <ul v-else>
217
+ <li v-for="mod in modules" :key="mod.id">
218
+ {{ mod.id }} ({{ mod.size }} bytes)
219
+ </li>
220
+ </ul>
221
+ </div>
222
+ </template>
223
+ ```
224
+
225
+ ## Vite Config for Client (src/client/vite.config.ts)
226
+
227
+ ```ts
228
+ import vue from '@vitejs/plugin-vue'
229
+ import { defineConfig } from 'vite'
230
+
231
+ export default defineConfig({
232
+ plugins: [vue()],
233
+ build: {
234
+ outDir: '../../dist/client',
235
+ emptyOutDir: true,
236
+ },
237
+ })
238
+ ```
239
+
240
+ ## Real-World References
241
+
242
+ ### In-Repo Examples
243
+
244
+ Reference these for code structure and patterns when building new integrations:
245
+
246
+ - [`examples/plugin-a11y-checker`](https://github.com/vitejs/devtools/tree/main/examples/plugin-a11y-checker) — Action entry, client-side audits, logs with element positions, log handle updates
247
+ - [`examples/plugin-file-explorer`](https://github.com/vitejs/devtools/tree/main/examples/plugin-file-explorer) — Iframe entry, multiple RPC types, hosted UI panel, RPC dump for static builds
248
+
249
+ ### Internal Packages
250
+
251
+ See [packages/vite](https://github.com/vitejs/devtools/tree/main/packages/vite) for a complete implementation with:
252
+
253
+ - Multiple RPC functions organized by feature
254
+ - Nuxt-based client UI
255
+ - Complex data visualization
256
+ - Build session management
@@ -0,0 +1,185 @@
1
+ # RPC Patterns
2
+
3
+ Advanced patterns for server-client communication in DevTools integrations.
4
+
5
+ ## Function Types
6
+
7
+ | Type | Caching | Use Case |
8
+ |------|---------|----------|
9
+ | `query` | Can be cached | Read operations, data fetching |
10
+ | `action` | Never cached | Mutations, side effects |
11
+ | `static` | Cached indefinitely | Constants, configuration |
12
+
13
+ ## Type-Safe RPC Setup
14
+
15
+ ### Step 1: Define Types
16
+
17
+ ```ts
18
+ // src/types.ts
19
+ import '@vitejs/devtools-kit'
20
+
21
+ interface Module {
22
+ id: string
23
+ size: number
24
+ imports: string[]
25
+ }
26
+
27
+ declare module '@vitejs/devtools-kit' {
28
+ interface DevToolsRpcServerFunctions {
29
+ 'my-plugin:list-modules': () => Promise<Module[]>
30
+ 'my-plugin:get-module': (id: string) => Promise<Module | null>
31
+ 'my-plugin:analyze': (options: { deep: boolean }) => Promise<void>
32
+ }
33
+
34
+ interface DevToolsRpcClientFunctions {
35
+ 'my-plugin:highlight': (selector: string) => void
36
+ 'my-plugin:refresh': () => void
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### Step 2: Import Types File
42
+
43
+ ```ts
44
+ // src/node/plugin.ts
45
+ import '../types' // Side-effect import for type augmentation
46
+ ```
47
+
48
+ ### Step 3: Register Functions
49
+
50
+ ```ts
51
+ import { defineRpcFunction } from '@vitejs/devtools-kit'
52
+
53
+ const listModules = defineRpcFunction({
54
+ name: 'my-plugin:list-modules',
55
+ type: 'query',
56
+ setup: () => ({
57
+ handler: async (): Promise<Module[]> => {
58
+ return Array.from(moduleMap.values())
59
+ },
60
+ }),
61
+ })
62
+ ```
63
+
64
+ ## Context Access in Setup
65
+
66
+ The `setup` function receives the full `DevToolsNodeContext`:
67
+
68
+ ```ts
69
+ defineRpcFunction({
70
+ name: 'my-plugin:get-config',
71
+ type: 'static',
72
+ setup: (ctx) => {
73
+ // Access at setup time (runs once)
74
+ const root = ctx.viteConfig.root
75
+ const isDev = ctx.mode === 'dev'
76
+
77
+ return {
78
+ handler: async () => ({
79
+ root,
80
+ isDev,
81
+ plugins: ctx.viteConfig.plugins.map(p => p.name),
82
+ }),
83
+ }
84
+ },
85
+ })
86
+ ```
87
+
88
+ ## Broadcasting Patterns
89
+
90
+ ### Basic Broadcast
91
+
92
+ ```ts
93
+ // Notify all clients
94
+ ctx.rpc.broadcast({
95
+ method: 'my-plugin:refresh',
96
+ args: [],
97
+ })
98
+ ```
99
+
100
+ ### Broadcast with Data
101
+
102
+ ```ts
103
+ ctx.viteServer?.watcher.on('change', (file) => {
104
+ ctx.rpc.broadcast({
105
+ method: 'my-plugin:file-changed',
106
+ args: [{ path: file, timestamp: Date.now() }],
107
+ })
108
+ })
109
+ ```
110
+
111
+ ### Optional Broadcast
112
+
113
+ ```ts
114
+ // Won't error if no clients have registered the function
115
+ ctx.rpc.broadcast({
116
+ method: 'my-plugin:optional-update',
117
+ args: [data],
118
+ optional: true,
119
+ })
120
+ ```
121
+
122
+ ## Client Function Registration
123
+
124
+ ```ts
125
+ // Client-side (action/renderer script)
126
+ export default function setup(ctx: DevToolsClientScriptContext) {
127
+ ctx.current.rpc.client.register({
128
+ name: 'my-plugin:highlight',
129
+ type: 'action',
130
+ handler: (selector: string) => {
131
+ const el = document.querySelector(selector)
132
+ if (el) {
133
+ el.style.outline = '3px solid red'
134
+ setTimeout(() => {
135
+ el.style.outline = ''
136
+ }, 2000)
137
+ }
138
+ },
139
+ })
140
+ }
141
+ ```
142
+
143
+ ## Collecting RPC Functions
144
+
145
+ Organize RPC functions in a registry pattern:
146
+
147
+ ```ts
148
+ import { analyzeBundle } from './functions/analyze-bundle'
149
+ // src/node/rpc/index.ts
150
+ import { getModules } from './functions/get-modules'
151
+ import { getStats } from './functions/get-stats'
152
+
153
+ export const rpcFunctions = [
154
+ getModules,
155
+ getStats,
156
+ analyzeBundle,
157
+ ] as const
158
+
159
+ // Register all in setup
160
+ for (const fn of rpcFunctions) {
161
+ ctx.rpc.register(fn)
162
+ }
163
+ ```
164
+
165
+ ## Type Extraction Utilities
166
+
167
+ ```ts
168
+ import type {
169
+ RpcDefinitionsFilter,
170
+ RpcDefinitionsToFunctions,
171
+ } from '@vitejs/devtools-kit'
172
+
173
+ // Extract all function types
174
+ export type ServerFunctions = RpcDefinitionsToFunctions<typeof rpcFunctions>
175
+
176
+ // Extract only static functions
177
+ export type StaticFunctions = RpcDefinitionsToFunctions<
178
+ RpcDefinitionsFilter<typeof rpcFunctions, 'static'>
179
+ >
180
+
181
+ // Augment the global interface
182
+ declare module '@vitejs/devtools-kit' {
183
+ export interface DevToolsRpcServerFunctions extends ServerFunctions {}
184
+ }
185
+ ```