Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/kit/logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The Logs system allows plugins to emit structured log entries from both the serv
| `status` | `'loading' \| 'idle'` | No | Status indicator (shows spinner when `'loading'`) |
| `id` | `string` | No | Explicit id for deduplication — re-adding with the same id updates the existing entry |

The `source` field is automatically set to `'server'` or `'client'` depending on where the log was emitted.
The `from` field is automatically set to `'server'` or `'browser'` depending on where the log was emitted.

## Usage

Expand Down
119 changes: 115 additions & 4 deletions skills/vite-devtools-kit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ name: writing-vite-devtools-integrations
description: >
Creates devtools integrations for Vite using @vitejs/devtools-kit.
Use when building Vite plugins with devtools panels, RPC functions,
dock entries, shared state, or any devtools-related functionality.
Applies to files importing from @vitejs/devtools-kit or containing
devtools.setup hooks in Vite plugins.
dock entries, shared state, logs/notifications, or any devtools-related
functionality. Applies to files importing from @vitejs/devtools-kit or
containing devtools.setup hooks in Vite plugins.
---

# Vite DevTools Kit
Expand All @@ -18,10 +18,11 @@ A DevTools plugin extends a Vite plugin with a `devtools.setup(ctx)` hook. The c

| Property | Purpose |
|----------|---------|
| `ctx.docks` | Register dock entries (iframe, action, custom-render) |
| `ctx.docks` | Register dock entries (iframe, action, custom-render, launcher) |
| `ctx.views` | Host static files for UI |
| `ctx.rpc` | Register RPC functions, broadcast to clients |
| `ctx.rpc.sharedState` | Synchronized server-client state |
| `ctx.logs` | Emit structured log entries and toast notifications |
| `ctx.viteConfig` | Resolved Vite configuration |
| `ctx.viteServer` | Dev server instance (dev mode only) |
| `ctx.mode` | `'dev'` or `'build'` |
Expand Down Expand Up @@ -123,6 +124,7 @@ export default function myAnalyzer(): Plugin {
| `iframe` | Full UI panels, dashboards (most common) |
| `action` | Buttons that trigger client-side scripts (inspectors, toggles) |
| `custom-render` | Direct DOM access in panel (framework mounting) |
| `launcher` | Actionable setup cards for initialization tasks |

### Iframe Entry

Expand Down Expand Up @@ -166,6 +168,89 @@ ctx.docks.register({
})
```

### Launcher Entry

```ts
const entry = ctx.docks.register({
id: 'my-setup',
title: 'My Setup',
icon: 'ph:rocket-launch-duotone',
type: 'launcher',
launcher: {
title: 'Initialize My Plugin',
description: 'Run initial setup before using the plugin',
buttonStart: 'Start Setup',
buttonLoading: 'Setting up...',
onLaunch: async () => {
// Run initialization logic
},
},
})
```

## Logs & Notifications

Plugins can emit structured log entries from both server and client contexts. Logs appear in the built-in **Logs** panel and can optionally show as toast notifications.

### Fire-and-Forget

```ts
// No await needed
context.logs.add({
message: 'Plugin initialized',
level: 'info',
})
```

### With Handle

```ts
const handle = await context.logs.add({
id: 'my-build',
message: 'Building...',
level: 'info',
status: 'loading',
})

// Update later
await handle.update({
message: 'Build complete',
level: 'success',
status: 'idle',
})

// Or dismiss
await handle.dismiss()
```

### Key Fields

| Field | Type | Description |
|-------|------|-------------|
| `message` | `string` | Short title (required) |
| `level` | `'info' \| 'warn' \| 'error' \| 'success' \| 'debug'` | Severity (required) |
| `description` | `string` | Detailed description |
| `notify` | `boolean` | Show as toast notification |
| `filePosition` | `{ file, line?, column? }` | Source file location (clickable) |
| `elementPosition` | `{ selector?, boundingBox?, description? }` | DOM element position |
| `id` | `string` | Explicit id for deduplication |
| `status` | `'loading' \| 'idle'` | Shows spinner when loading |
| `category` | `string` | Grouping (e.g., `'a11y'`, `'lint'`) |
| `labels` | `string[]` | Tags for filtering |
| `autoDismiss` | `number` | Toast auto-dismiss time in ms (default: 5000) |
| `autoDelete` | `number` | Auto-delete time in ms |

The `from` field is automatically set to `'server'` or `'browser'`.

### Deduplication

Re-adding with the same `id` updates the existing entry instead of creating a duplicate:

```ts
context.logs.add({ id: 'my-scan', message: 'Scanning...', level: 'info', status: 'loading' })
context.logs.add({ id: 'my-scan', message: 'Scan complete', level: 'success', status: 'idle' })
```

## RPC Functions

### Server-Side Definition
Expand Down Expand Up @@ -308,6 +393,22 @@ Export from package.json:
}
```

## Debugging with Self-Inspect

Use `@vitejs/devtools-self-inspect` to debug your DevTools plugin. It shows registered RPC functions, dock entries, client scripts, and plugins in a meta-introspection UI at `/.devtools-self-inspect/`.

```ts
import DevTools from '@vitejs/devtools'
import DevToolsSelfInspect from '@vitejs/devtools-self-inspect'

export default defineConfig({
plugins: [
DevTools(),
DevToolsSelfInspect(),
],
})
```

## Best Practices

1. **Always namespace** - Prefix all identifiers with your plugin name
Expand All @@ -316,10 +417,20 @@ Export from package.json:
4. **Batch mutations** - Use single `mutate()` call for multiple changes
5. **Host static files** - Use `ctx.views.hostStatic()` for your UI assets
6. **Use Iconify icons** - Prefer `ph:*` (Phosphor) icons: `icon: 'ph:chart-bar-duotone'`
7. **Deduplicate logs** - Use explicit `id` for logs representing ongoing operations
8. **Use Self-Inspect** - Add `@vitejs/devtools-self-inspect` during development to debug your plugin

## Example Plugins

Real-world example plugins in the repo — reference their code structure and patterns when building new integrations:

- **A11y Checker** ([`examples/plugin-a11y-checker`](https://github.com/vitejs/devtools/tree/main/examples/plugin-a11y-checker)) — Action dock entry, client-side axe-core audits, logs with severity levels and element positions, log handle updates
- **File Explorer** ([`examples/plugin-file-explorer`](https://github.com/vitejs/devtools/tree/main/examples/plugin-file-explorer)) — Iframe dock entry, RPC functions (static/query/action), hosted UI panel, RPC dump for static builds, backend mode detection

## Further Reading

- [RPC Patterns](./references/rpc-patterns.md) - Advanced RPC patterns and type utilities
- [Dock Entry Types](./references/dock-entry-types.md) - Detailed dock configuration options
- [Shared State Patterns](./references/shared-state-patterns.md) - Framework integration examples
- [Project Structure](./references/project-structure.md) - Recommended file organization
- [Logs Patterns](./references/logs-patterns.md) - Log entries, toast notifications, and handle patterns
55 changes: 55 additions & 0 deletions skills/vite-devtools-kit/references/dock-entry-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ interface DockEntryBase {
category?: string // Grouping category
defaultOrder?: number // Sort order (higher = earlier)
isHidden?: boolean // Hide from dock
badge?: string // Badge text on dock icon (e.g., count)
}
```

Expand Down Expand Up @@ -200,6 +201,60 @@ export default function setup(ctx: DevToolsClientScriptContext) {
}
```

## Launcher Entries

Actionable setup cards for running initialization tasks. Shows a card with title, description, and a launch button.

```ts
type LauncherStatus = 'idle' | 'loading' | 'success' | 'error'

interface LauncherEntry extends DockEntryBase {
type: 'launcher'
launcher: {
title: string // Card title
description?: string // Card description
icon?: string | { light: string, dark: string } // Card icon
buttonStart?: string // Start button text
buttonLoading?: string // Loading button text
status?: LauncherStatus // Current status
error?: string // Error message when status is 'error'
onLaunch: () => Promise<void> // Callback when user clicks launch
}
}

// Registration
const entry = ctx.docks.register({
id: 'my-setup',
title: 'My Setup',
icon: 'ph:rocket-launch-duotone',
type: 'launcher',
launcher: {
title: 'Initialize My Plugin',
description: 'Run the initial setup before the plugin can be used',
buttonStart: 'Start Setup',
buttonLoading: 'Setting up...',
onLaunch: async () => {
// Perform initialization
await runSetup()
},
},
})

// Update status after launch completes
entry.update({
launcher: {
...entry.launcher,
status: 'success',
},
})
```

### Launcher Use Cases

- **First-run setup** — Run initial scans or configuration before showing results
- **Build triggers** — Start a build or analysis pass on demand
- **Authentication** — Prompt user to connect external services

## Client Script Events

| Event | Payload | Description |
Expand Down
Loading
Loading