@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,295 @@
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
+ badge?: string // Badge text on dock icon (e.g., count)
18
+ }
19
+ ```
20
+
21
+ ## Icons
22
+
23
+ <!-- eslint-skip -->
24
+
25
+ ```ts
26
+ // Iconify (recommended)
27
+ icon: 'ph:chart-bar-duotone' // Phosphor Icons
28
+ icon: 'carbon:analytics' // Carbon Icons
29
+ icon: 'mdi:view-dashboard' // Material Design
30
+
31
+ // URL
32
+ icon: 'https://example.com/logo.svg'
33
+
34
+ // Data URI
35
+ icon: 'data:image/svg+xml,<svg>...</svg>'
36
+
37
+ // Light/dark variants
38
+ icon: {
39
+ light: 'https://example.com/logo-light.svg',
40
+ dark: 'https://example.com/logo-dark.svg',
41
+ }
42
+ ```
43
+
44
+ Browse icons at [Iconify](https://icon-sets.iconify.design/).
45
+
46
+ ## Iframe Entries
47
+
48
+ Most common type. Displays your UI in an isolated iframe.
49
+
50
+ ```ts
51
+ interface IframeEntry extends DockEntryBase {
52
+ type: 'iframe'
53
+ url: string // URL to load
54
+ frameId?: string // Share iframe between entries
55
+ clientScript?: ClientScriptEntry // Optional client script
56
+ }
57
+
58
+ // Example
59
+ ctx.docks.register({
60
+ id: 'my-plugin',
61
+ title: 'My Plugin',
62
+ icon: 'ph:house-duotone',
63
+ type: 'iframe',
64
+ url: '/.my-plugin/',
65
+ })
66
+ ```
67
+
68
+ ### Hosting Your Own UI
69
+
70
+ ```ts
71
+ import { fileURLToPath } from 'node:url'
72
+
73
+ const clientDist = fileURLToPath(
74
+ new URL('../dist/client', import.meta.url)
75
+ )
76
+
77
+ ctx.views.hostStatic('/.my-plugin/', clientDist)
78
+
79
+ ctx.docks.register({
80
+ id: 'my-plugin',
81
+ title: 'My Plugin',
82
+ icon: 'ph:house-duotone',
83
+ type: 'iframe',
84
+ url: '/.my-plugin/',
85
+ })
86
+ ```
87
+
88
+ ## Action Entries
89
+
90
+ Buttons that trigger client-side scripts. Perfect for inspectors and toggles.
91
+
92
+ ```ts
93
+ interface ActionEntry extends DockEntryBase {
94
+ type: 'action'
95
+ action: {
96
+ importFrom: string // Package export path
97
+ importName?: string // Export name (default: 'default')
98
+ }
99
+ }
100
+
101
+ // Registration
102
+ ctx.docks.register({
103
+ id: 'my-inspector',
104
+ title: 'Inspector',
105
+ icon: 'ph:cursor-duotone',
106
+ type: 'action',
107
+ action: {
108
+ importFrom: 'my-plugin/devtools-action',
109
+ importName: 'default',
110
+ },
111
+ })
112
+ ```
113
+
114
+ ### Client Script Implementation
115
+
116
+ ```ts
117
+ // src/devtools-action.ts
118
+ import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
119
+
120
+ export default function setup(ctx: DevToolsClientScriptContext) {
121
+ let overlay: HTMLElement | null = null
122
+
123
+ ctx.current.events.on('entry:activated', () => {
124
+ overlay = document.createElement('div')
125
+ overlay.style.cssText = `
126
+ position: fixed;
127
+ inset: 0;
128
+ cursor: crosshair;
129
+ z-index: 99999;
130
+ `
131
+ overlay.onclick = (e) => {
132
+ const target = document.elementFromPoint(e.clientX, e.clientY)
133
+ console.log('Selected:', target)
134
+ }
135
+ document.body.appendChild(overlay)
136
+ })
137
+
138
+ ctx.current.events.on('entry:deactivated', () => {
139
+ overlay?.remove()
140
+ overlay = null
141
+ })
142
+ }
143
+ ```
144
+
145
+ ### Package Export
146
+
147
+ ```json
148
+ {
149
+ "exports": {
150
+ ".": "./dist/index.mjs",
151
+ "./devtools-action": "./dist/devtools-action.mjs"
152
+ }
153
+ }
154
+ ```
155
+
156
+ ## Custom Render Entries
157
+
158
+ Render directly into the DevTools panel DOM. Use when you need direct DOM access or framework mounting.
159
+
160
+ ```ts
161
+ interface CustomRenderEntry extends DockEntryBase {
162
+ type: 'custom-render'
163
+ renderer: {
164
+ importFrom: string
165
+ importName?: string
166
+ }
167
+ }
168
+
169
+ ctx.docks.register({
170
+ id: 'my-custom',
171
+ title: 'Custom View',
172
+ icon: 'ph:code-duotone',
173
+ type: 'custom-render',
174
+ renderer: {
175
+ importFrom: 'my-plugin/devtools-renderer',
176
+ importName: 'default',
177
+ },
178
+ })
179
+ ```
180
+
181
+ ### Renderer Implementation
182
+
183
+ ```ts
184
+ // src/devtools-renderer.ts
185
+ import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
186
+
187
+ export default function setup(ctx: DevToolsClientScriptContext) {
188
+ ctx.current.events.on('dom:panel:mounted', (panel) => {
189
+ // Vanilla JS
190
+ panel.innerHTML = `<div style="padding: 16px;">Hello</div>`
191
+
192
+ // Or mount Vue
193
+ // import { createApp } from 'vue'
194
+ // import App from './App.vue'
195
+ // createApp(App).mount(panel)
196
+
197
+ // Or mount React
198
+ // import { createRoot } from 'react-dom/client'
199
+ // createRoot(panel).render(<App />)
200
+ })
201
+ }
202
+ ```
203
+
204
+ ## Launcher Entries
205
+
206
+ Actionable setup cards for running initialization tasks. Shows a card with title, description, and a launch button.
207
+
208
+ ```ts
209
+ type LauncherStatus = 'idle' | 'loading' | 'success' | 'error'
210
+
211
+ interface LauncherEntry extends DockEntryBase {
212
+ type: 'launcher'
213
+ launcher: {
214
+ title: string // Card title
215
+ description?: string // Card description
216
+ icon?: string | { light: string, dark: string } // Card icon
217
+ buttonStart?: string // Start button text
218
+ buttonLoading?: string // Loading button text
219
+ status?: LauncherStatus // Current status
220
+ error?: string // Error message when status is 'error'
221
+ onLaunch: () => Promise<void> // Callback when user clicks launch
222
+ }
223
+ }
224
+
225
+ // Registration
226
+ const entry = ctx.docks.register({
227
+ id: 'my-setup',
228
+ title: 'My Setup',
229
+ icon: 'ph:rocket-launch-duotone',
230
+ type: 'launcher',
231
+ launcher: {
232
+ title: 'Initialize My Plugin',
233
+ description: 'Run the initial setup before the plugin can be used',
234
+ buttonStart: 'Start Setup',
235
+ buttonLoading: 'Setting up...',
236
+ onLaunch: async () => {
237
+ // Perform initialization
238
+ await runSetup()
239
+ },
240
+ },
241
+ })
242
+
243
+ // Update status after launch completes
244
+ entry.update({
245
+ launcher: {
246
+ ...entry.launcher,
247
+ status: 'success',
248
+ },
249
+ })
250
+ ```
251
+
252
+ ### Launcher Use Cases
253
+
254
+ - **First-run setup** — Run initial scans or configuration before showing results
255
+ - **Build triggers** — Start a build or analysis pass on demand
256
+ - **Authentication** — Prompt user to connect external services
257
+
258
+ ## Client Script Events
259
+
260
+ | Event | Payload | Description |
261
+ |-------|---------|-------------|
262
+ | `entry:activated` | - | Entry was selected |
263
+ | `entry:deactivated` | - | Entry was deselected |
264
+ | `entry:updated` | `DevToolsDockUserEntry` | Entry metadata changed |
265
+ | `dom:panel:mounted` | `HTMLDivElement` | Panel DOM ready (custom-render only) |
266
+ | `dom:iframe:mounted` | `HTMLIFrameElement` | Iframe mounted (iframe only) |
267
+
268
+ ## Category Order
269
+
270
+ Default category ordering:
271
+
272
+ ```ts
273
+ DEFAULT_CATEGORIES_ORDER = {
274
+ '~viteplus': -1000, // First
275
+ 'default': 0,
276
+ 'app': 100,
277
+ 'framework': 200,
278
+ 'web': 300,
279
+ 'advanced': 400,
280
+ '~builtin': 1000, // Last
281
+ }
282
+ ```
283
+
284
+ Use `category` to group related entries:
285
+
286
+ ```ts
287
+ ctx.docks.register({
288
+ id: 'my-plugin',
289
+ title: 'My Plugin',
290
+ icon: 'ph:house-duotone',
291
+ type: 'iframe',
292
+ url: '/.my-plugin/',
293
+ category: 'framework',
294
+ })
295
+ ```
@@ -0,0 +1,188 @@
1
+ # Logs & Notification Patterns
2
+
3
+ Structured log entries and toast notifications from both server and client contexts.
4
+
5
+ ## Log Entry Types
6
+
7
+ ```ts
8
+ type DevToolsLogLevel = 'info' | 'warn' | 'error' | 'success' | 'debug'
9
+
10
+ interface DevToolsLogEntryInput {
11
+ message: string // Required: short title
12
+ level: DevToolsLogLevel // Required: severity
13
+ description?: string // Detailed explanation
14
+ stacktrace?: string // Stack trace string
15
+ filePosition?: { file: string, line?: number, column?: number }
16
+ elementPosition?: { selector?: string, boundingBox?: { x: number, y: number, width: number, height: number }, description?: string }
17
+ notify?: boolean // Show as toast
18
+ category?: string // Grouping (e.g., 'a11y', 'lint')
19
+ labels?: string[] // Tags for filtering
20
+ autoDismiss?: number // Toast dismiss time in ms (default: 5000)
21
+ autoDelete?: number // Auto-delete time in ms
22
+ status?: 'loading' | 'idle' // Shows spinner when loading
23
+ id?: string // Explicit id for deduplication
24
+ }
25
+ ```
26
+
27
+ The `from` field (`'server' | 'browser'`) is set automatically.
28
+
29
+ ## Server-Side Patterns
30
+
31
+ ### Fire-and-Forget in Setup
32
+
33
+ ```ts
34
+ export function myPlugin() {
35
+ return {
36
+ name: 'my-plugin',
37
+ devtools: {
38
+ setup(ctx) {
39
+ ctx.logs.add({
40
+ message: 'Plugin initialized',
41
+ level: 'info',
42
+ })
43
+ },
44
+ },
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Handle-Based Updates
50
+
51
+ ```ts
52
+ export function myPlugin() {
53
+ return {
54
+ name: 'my-plugin',
55
+ devtools: {
56
+ async setup(ctx) {
57
+ const log = await ctx.logs.add({
58
+ id: 'my-plugin:build',
59
+ message: 'Analyzing...',
60
+ level: 'info',
61
+ status: 'loading',
62
+ })
63
+
64
+ // Later, after work completes
65
+ await log.update({
66
+ message: 'Analysis complete — 42 modules',
67
+ level: 'success',
68
+ status: 'idle',
69
+ })
70
+ },
71
+ },
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### File Position (Clickable Links)
77
+
78
+ ```ts
79
+ ctx.logs.add({
80
+ message: 'Unused import detected',
81
+ level: 'warn',
82
+ category: 'lint',
83
+ filePosition: {
84
+ file: '/src/App.vue',
85
+ line: 12,
86
+ column: 1,
87
+ },
88
+ })
89
+ ```
90
+
91
+ ### Element Position (DOM Highlighting)
92
+
93
+ ```ts
94
+ ctx.logs.add({
95
+ message: 'Missing alt attribute on image',
96
+ level: 'warn',
97
+ category: 'a11y',
98
+ labels: ['WCAG 1.1.1'],
99
+ elementPosition: {
100
+ selector: 'img.hero-image',
101
+ description: '<img class="hero-image">',
102
+ },
103
+ })
104
+ ```
105
+
106
+ ## Client-Side Patterns
107
+
108
+ ### Client Script with Logs
109
+
110
+ ```ts
111
+ import type { DockClientScriptContext } from '@vitejs/devtools-kit/client'
112
+
113
+ export default async function (ctx: DockClientScriptContext) {
114
+ const log = await ctx.logs.add({
115
+ message: 'Running audit...',
116
+ level: 'info',
117
+ status: 'loading',
118
+ notify: true,
119
+ })
120
+
121
+ // ... perform work ...
122
+
123
+ log.update({
124
+ message: 'Audit complete — 3 issues found',
125
+ level: 'warn',
126
+ status: 'idle',
127
+ })
128
+ }
129
+ ```
130
+
131
+ ## Toast Notifications
132
+
133
+ ```ts
134
+ // Short-lived notification
135
+ ctx.logs.add({
136
+ message: 'URL copied to clipboard',
137
+ level: 'success',
138
+ notify: true,
139
+ autoDismiss: 2000,
140
+ })
141
+ ```
142
+
143
+ Toasts appear as overlay notifications regardless of whether the Logs panel is open. Default auto-dismiss is 5 seconds.
144
+
145
+ ## Deduplication
146
+
147
+ Re-adding with the same `id` updates the existing entry:
148
+
149
+ ```ts
150
+ // Creates entry
151
+ ctx.logs.add({ id: 'my-scan', message: 'Scanning...', level: 'info', status: 'loading' })
152
+
153
+ // Updates same entry (no duplicate)
154
+ ctx.logs.add({ id: 'my-scan', message: 'Scan complete', level: 'success', status: 'idle' })
155
+ ```
156
+
157
+ ## Log Handle API
158
+
159
+ `ctx.logs.add()` returns `Promise<DevToolsLogHandle>`:
160
+
161
+ | Property/Method | Description |
162
+ |-----------------|-------------|
163
+ | `handle.id` | The log entry id |
164
+ | `handle.entry` | The current `DevToolsLogEntry` data |
165
+ | `handle.update(patch)` | Partially update the entry (returns `Promise`) |
166
+ | `handle.dismiss()` | Remove the entry (returns `Promise`) |
167
+
168
+ Both `update()` and `dismiss()` can be used without `await` for fire-and-forget.
169
+
170
+ ## Managing Logs
171
+
172
+ ```ts
173
+ // Remove specific log
174
+ ctx.logs.remove(entryId)
175
+
176
+ // Clear all logs
177
+ ctx.logs.clear()
178
+ ```
179
+
180
+ Max capacity is 1000 entries; oldest entries are auto-removed when full.
181
+
182
+ ## Dock Badge
183
+
184
+ The built-in Logs dock icon automatically shows a badge with the total log count and is hidden when empty.
185
+
186
+ ## Real-World Example
187
+
188
+ See [`examples/plugin-a11y-checker`](https://github.com/vitejs/devtools/tree/main/examples/plugin-a11y-checker) for a complete plugin that uses logs to report accessibility violations with severity levels, element positions, WCAG labels, and log handle updates.