From ea89cc431f0d6a5da42f1f4bf33cd10d84d72917 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 13 Mar 2026 11:47:41 +0900 Subject: [PATCH] docs: update Vite DevTools Kit skills with recent features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive documentation for: - Logs & notifications system (fire-and-forget, handles, deduplication, toasts) - Launcher dock entry type (setup cards for initialization) - Self-Inspect debugging plugin (@vitejs/devtools-self-inspect) - Updated field name reference (source → from) in docs - Launcher usage in dock-entry-types.md and badge property - Setup-time shared state initialization - Example plugin references for agents and developers Also create new logs-patterns.md reference file with complete patterns and examples. Co-Authored-By: Claude Haiku 4.5 --- docs/kit/logs.md | 2 +- skills/vite-devtools-kit/SKILL.md | 119 ++++++++++- .../references/dock-entry-types.md | 55 +++++ .../references/logs-patterns.md | 188 ++++++++++++++++++ .../references/project-structure.md | 13 +- .../references/shared-state-patterns.md | 2 + 6 files changed, 372 insertions(+), 7 deletions(-) create mode 100644 skills/vite-devtools-kit/references/logs-patterns.md diff --git a/docs/kit/logs.md b/docs/kit/logs.md index 42e86de0..d55a2323 100644 --- a/docs/kit/logs.md +++ b/docs/kit/logs.md @@ -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 diff --git a/skills/vite-devtools-kit/SKILL.md b/skills/vite-devtools-kit/SKILL.md index a1e828cc..40fb88c8 100644 --- a/skills/vite-devtools-kit/SKILL.md +++ b/skills/vite-devtools-kit/SKILL.md @@ -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 @@ -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'` | @@ -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 @@ -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 @@ -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 @@ -316,6 +417,15 @@ 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 @@ -323,3 +433,4 @@ Export from package.json: - [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 diff --git a/skills/vite-devtools-kit/references/dock-entry-types.md b/skills/vite-devtools-kit/references/dock-entry-types.md index 8d8a3c66..12e46d21 100644 --- a/skills/vite-devtools-kit/references/dock-entry-types.md +++ b/skills/vite-devtools-kit/references/dock-entry-types.md @@ -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) } ``` @@ -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 // 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 | diff --git a/skills/vite-devtools-kit/references/logs-patterns.md b/skills/vite-devtools-kit/references/logs-patterns.md new file mode 100644 index 00000000..e8f36e6a --- /dev/null +++ b/skills/vite-devtools-kit/references/logs-patterns.md @@ -0,0 +1,188 @@ +# Logs & Notification Patterns + +Structured log entries and toast notifications from both server and client contexts. + +## Log Entry Types + +```ts +type DevToolsLogLevel = 'info' | 'warn' | 'error' | 'success' | 'debug' + +interface DevToolsLogEntryInput { + message: string // Required: short title + level: DevToolsLogLevel // Required: severity + description?: string // Detailed explanation + stacktrace?: string // Stack trace string + filePosition?: { file: string, line?: number, column?: number } + elementPosition?: { selector?: string, boundingBox?: { x: number, y: number, width: number, height: number }, description?: string } + notify?: boolean // Show as toast + category?: string // Grouping (e.g., 'a11y', 'lint') + labels?: string[] // Tags for filtering + autoDismiss?: number // Toast dismiss time in ms (default: 5000) + autoDelete?: number // Auto-delete time in ms + status?: 'loading' | 'idle' // Shows spinner when loading + id?: string // Explicit id for deduplication +} +``` + +The `from` field (`'server' | 'browser'`) is set automatically. + +## Server-Side Patterns + +### Fire-and-Forget in Setup + +```ts +export function myPlugin() { + return { + name: 'my-plugin', + devtools: { + setup(ctx) { + ctx.logs.add({ + message: 'Plugin initialized', + level: 'info', + }) + }, + }, + } +} +``` + +### Handle-Based Updates + +```ts +export function myPlugin() { + return { + name: 'my-plugin', + devtools: { + async setup(ctx) { + const log = await ctx.logs.add({ + id: 'my-plugin:build', + message: 'Analyzing...', + level: 'info', + status: 'loading', + }) + + // Later, after work completes + await log.update({ + message: 'Analysis complete — 42 modules', + level: 'success', + status: 'idle', + }) + }, + }, + } +} +``` + +### File Position (Clickable Links) + +```ts +ctx.logs.add({ + message: 'Unused import detected', + level: 'warn', + category: 'lint', + filePosition: { + file: '/src/App.vue', + line: 12, + column: 1, + }, +}) +``` + +### Element Position (DOM Highlighting) + +```ts +ctx.logs.add({ + message: 'Missing alt attribute on image', + level: 'warn', + category: 'a11y', + labels: ['WCAG 1.1.1'], + elementPosition: { + selector: 'img.hero-image', + description: '', + }, +}) +``` + +## Client-Side Patterns + +### Client Script with Logs + +```ts +import type { DockClientScriptContext } from '@vitejs/devtools-kit/client' + +export default async function (ctx: DockClientScriptContext) { + const log = await ctx.logs.add({ + message: 'Running audit...', + level: 'info', + status: 'loading', + notify: true, + }) + + // ... perform work ... + + log.update({ + message: 'Audit complete — 3 issues found', + level: 'warn', + status: 'idle', + }) +} +``` + +## Toast Notifications + +```ts +// Short-lived notification +ctx.logs.add({ + message: 'URL copied to clipboard', + level: 'success', + notify: true, + autoDismiss: 2000, +}) +``` + +Toasts appear as overlay notifications regardless of whether the Logs panel is open. Default auto-dismiss is 5 seconds. + +## Deduplication + +Re-adding with the same `id` updates the existing entry: + +```ts +// Creates entry +ctx.logs.add({ id: 'my-scan', message: 'Scanning...', level: 'info', status: 'loading' }) + +// Updates same entry (no duplicate) +ctx.logs.add({ id: 'my-scan', message: 'Scan complete', level: 'success', status: 'idle' }) +``` + +## Log Handle API + +`ctx.logs.add()` returns `Promise`: + +| Property/Method | Description | +|-----------------|-------------| +| `handle.id` | The log entry id | +| `handle.entry` | The current `DevToolsLogEntry` data | +| `handle.update(patch)` | Partially update the entry (returns `Promise`) | +| `handle.dismiss()` | Remove the entry (returns `Promise`) | + +Both `update()` and `dismiss()` can be used without `await` for fire-and-forget. + +## Managing Logs + +```ts +// Remove specific log +ctx.logs.remove(entryId) + +// Clear all logs +ctx.logs.clear() +``` + +Max capacity is 1000 entries; oldest entries are auto-removed when full. + +## Dock Badge + +The built-in Logs dock icon automatically shows a badge with the total log count and is hidden when empty. + +## Real-World Example + +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. diff --git a/skills/vite-devtools-kit/references/project-structure.md b/skills/vite-devtools-kit/references/project-structure.md index c74cc3e9..4aa23447 100644 --- a/skills/vite-devtools-kit/references/project-structure.md +++ b/skills/vite-devtools-kit/references/project-structure.md @@ -237,9 +237,18 @@ export default defineConfig({ }) ``` -## Real-World Reference +## Real-World References -See [packages/vite](https://github.com/user/vite-devtools/tree/main/packages/vite) for a complete implementation example with: +### In-Repo Examples + +Reference these for code structure and patterns when building new integrations: + +- [`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 +- [`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 + +### Internal Packages + +See [packages/vite](https://github.com/vitejs/devtools/tree/main/packages/vite) for a complete implementation with: - Multiple RPC functions organized by feature - Nuxt-based client UI diff --git a/skills/vite-devtools-kit/references/shared-state-patterns.md b/skills/vite-devtools-kit/references/shared-state-patterns.md index 1abad59c..32e8a301 100644 --- a/skills/vite-devtools-kit/references/shared-state-patterns.md +++ b/skills/vite-devtools-kit/references/shared-state-patterns.md @@ -4,6 +4,8 @@ Synchronized state between server and all clients. ## Basic Usage +Shared state is available during `devtools.setup()` — you can initialize it directly in the setup hook. + ### Server-Side ```ts