@vitejs/devtools-kit 0.0.0-alpha.3 → 0.0.0-alpha.31

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,240 @@
1
+ # Dock Entry Types
2
+
3
+ Detailed configuration for each dock entry type.
4
+
5
+ ## Common Properties
6
+
7
+ All dock entries share these properties:
8
+
9
+ ```ts
10
+ interface DockEntryBase {
11
+ id: string // Unique identifier
12
+ title: string // Display title
13
+ icon: string // URL, data URI, or Iconify name
14
+ category?: string // Grouping category
15
+ defaultOrder?: number // Sort order (higher = earlier)
16
+ isHidden?: boolean // Hide from dock
17
+ }
18
+ ```
19
+
20
+ ## Icons
21
+
22
+ <!-- eslint-skip -->
23
+
24
+ ```ts
25
+ // Iconify (recommended)
26
+ icon: 'ph:chart-bar-duotone' // Phosphor Icons
27
+ icon: 'carbon:analytics' // Carbon Icons
28
+ icon: 'mdi:view-dashboard' // Material Design
29
+
30
+ // URL
31
+ icon: 'https://example.com/logo.svg'
32
+
33
+ // Data URI
34
+ icon: 'data:image/svg+xml,<svg>...</svg>'
35
+
36
+ // Light/dark variants
37
+ icon: {
38
+ light: 'https://example.com/logo-light.svg',
39
+ dark: 'https://example.com/logo-dark.svg',
40
+ }
41
+ ```
42
+
43
+ Browse icons at [Iconify](https://icon-sets.iconify.design/).
44
+
45
+ ## Iframe Entries
46
+
47
+ Most common type. Displays your UI in an isolated iframe.
48
+
49
+ ```ts
50
+ interface IframeEntry extends DockEntryBase {
51
+ type: 'iframe'
52
+ url: string // URL to load
53
+ frameId?: string // Share iframe between entries
54
+ clientScript?: ClientScriptEntry // Optional client script
55
+ }
56
+
57
+ // Example
58
+ ctx.docks.register({
59
+ id: 'my-plugin',
60
+ title: 'My Plugin',
61
+ icon: 'ph:house-duotone',
62
+ type: 'iframe',
63
+ url: '/.my-plugin/',
64
+ })
65
+ ```
66
+
67
+ ### Hosting Your Own UI
68
+
69
+ ```ts
70
+ import { fileURLToPath } from 'node:url'
71
+
72
+ const clientDist = fileURLToPath(
73
+ new URL('../dist/client', import.meta.url)
74
+ )
75
+
76
+ ctx.views.hostStatic('/.my-plugin/', clientDist)
77
+
78
+ ctx.docks.register({
79
+ id: 'my-plugin',
80
+ title: 'My Plugin',
81
+ icon: 'ph:house-duotone',
82
+ type: 'iframe',
83
+ url: '/.my-plugin/',
84
+ })
85
+ ```
86
+
87
+ ## Action Entries
88
+
89
+ Buttons that trigger client-side scripts. Perfect for inspectors and toggles.
90
+
91
+ ```ts
92
+ interface ActionEntry extends DockEntryBase {
93
+ type: 'action'
94
+ action: {
95
+ importFrom: string // Package export path
96
+ importName?: string // Export name (default: 'default')
97
+ }
98
+ }
99
+
100
+ // Registration
101
+ ctx.docks.register({
102
+ id: 'my-inspector',
103
+ title: 'Inspector',
104
+ icon: 'ph:cursor-duotone',
105
+ type: 'action',
106
+ action: {
107
+ importFrom: 'my-plugin/devtools-action',
108
+ importName: 'default',
109
+ },
110
+ })
111
+ ```
112
+
113
+ ### Client Script Implementation
114
+
115
+ ```ts
116
+ // src/devtools-action.ts
117
+ import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
118
+
119
+ export default function setup(ctx: DevToolsClientScriptContext) {
120
+ let overlay: HTMLElement | null = null
121
+
122
+ ctx.current.events.on('entry:activated', () => {
123
+ overlay = document.createElement('div')
124
+ overlay.style.cssText = `
125
+ position: fixed;
126
+ inset: 0;
127
+ cursor: crosshair;
128
+ z-index: 99999;
129
+ `
130
+ overlay.onclick = (e) => {
131
+ const target = document.elementFromPoint(e.clientX, e.clientY)
132
+ console.log('Selected:', target)
133
+ }
134
+ document.body.appendChild(overlay)
135
+ })
136
+
137
+ ctx.current.events.on('entry:deactivated', () => {
138
+ overlay?.remove()
139
+ overlay = null
140
+ })
141
+ }
142
+ ```
143
+
144
+ ### Package Export
145
+
146
+ ```json
147
+ {
148
+ "exports": {
149
+ ".": "./dist/index.mjs",
150
+ "./devtools-action": "./dist/devtools-action.mjs"
151
+ }
152
+ }
153
+ ```
154
+
155
+ ## Custom Render Entries
156
+
157
+ Render directly into the DevTools panel DOM. Use when you need direct DOM access or framework mounting.
158
+
159
+ ```ts
160
+ interface CustomRenderEntry extends DockEntryBase {
161
+ type: 'custom-render'
162
+ renderer: {
163
+ importFrom: string
164
+ importName?: string
165
+ }
166
+ }
167
+
168
+ ctx.docks.register({
169
+ id: 'my-custom',
170
+ title: 'Custom View',
171
+ icon: 'ph:code-duotone',
172
+ type: 'custom-render',
173
+ renderer: {
174
+ importFrom: 'my-plugin/devtools-renderer',
175
+ importName: 'default',
176
+ },
177
+ })
178
+ ```
179
+
180
+ ### Renderer Implementation
181
+
182
+ ```ts
183
+ // src/devtools-renderer.ts
184
+ import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
185
+
186
+ export default function setup(ctx: DevToolsClientScriptContext) {
187
+ ctx.current.events.on('dom:panel:mounted', (panel) => {
188
+ // Vanilla JS
189
+ panel.innerHTML = `<div style="padding: 16px;">Hello</div>`
190
+
191
+ // Or mount Vue
192
+ // import { createApp } from 'vue'
193
+ // import App from './App.vue'
194
+ // createApp(App).mount(panel)
195
+
196
+ // Or mount React
197
+ // import { createRoot } from 'react-dom/client'
198
+ // createRoot(panel).render(<App />)
199
+ })
200
+ }
201
+ ```
202
+
203
+ ## Client Script Events
204
+
205
+ | Event | Payload | Description |
206
+ |-------|---------|-------------|
207
+ | `entry:activated` | - | Entry was selected |
208
+ | `entry:deactivated` | - | Entry was deselected |
209
+ | `entry:updated` | `DevToolsDockUserEntry` | Entry metadata changed |
210
+ | `dom:panel:mounted` | `HTMLDivElement` | Panel DOM ready (custom-render only) |
211
+ | `dom:iframe:mounted` | `HTMLIFrameElement` | Iframe mounted (iframe only) |
212
+
213
+ ## Category Order
214
+
215
+ Default category ordering:
216
+
217
+ ```ts
218
+ DEFAULT_CATEGORIES_ORDER = {
219
+ '~viteplus': -1000, // First
220
+ 'default': 0,
221
+ 'app': 100,
222
+ 'framework': 200,
223
+ 'web': 300,
224
+ 'advanced': 400,
225
+ '~builtin': 1000, // Last
226
+ }
227
+ ```
228
+
229
+ Use `category` to group related entries:
230
+
231
+ ```ts
232
+ ctx.docks.register({
233
+ id: 'my-plugin',
234
+ title: 'My Plugin',
235
+ icon: 'ph:house-duotone',
236
+ type: 'iframe',
237
+ url: '/.my-plugin/',
238
+ category: 'framework',
239
+ })
240
+ ```
@@ -0,0 +1,247 @@
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 Reference
241
+
242
+ See [packages/vite](https://github.com/user/vite-devtools/tree/main/packages/vite) for a complete implementation example with:
243
+
244
+ - Multiple RPC functions organized by feature
245
+ - Nuxt-based client UI
246
+ - Complex data visualization
247
+ - 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
+ ```