|
| 1 | +# Logs |
| 2 | + |
| 3 | +The Logs system allows plugins to emit structured log entries from both the server (Node.js) and client (browser) contexts. Logs are displayed in the built-in **Logs** panel in the DevTools dock, and can optionally appear as toast notifications. |
| 4 | + |
| 5 | +## Use Cases |
| 6 | + |
| 7 | +- **Accessibility audits** — Run axe or similar tools on the client side, report warnings with element positions and autofix suggestions |
| 8 | +- **Runtime errors** — Capture and display errors with stack traces |
| 9 | +- **Linting & testing** — Run ESLint or test runners alongside the dev server and surface results with file positions |
| 10 | +- **Notifications** — Short-lived messages like "URL copied" that auto-dismiss |
| 11 | + |
| 12 | +## Log Entry Fields |
| 13 | + |
| 14 | +| Field | Type | Required | Description | |
| 15 | +|-------|------|----------|-------------| |
| 16 | +| `message` | `string` | Yes | Short title or summary | |
| 17 | +| `level` | `'info' \| 'warn' \| 'error' \| 'success' \| 'debug'` | Yes | Severity level, determines color and icon | |
| 18 | +| `description` | `string` | No | Detailed description or explanation | |
| 19 | +| `stacktrace` | `string` | No | Stack trace string | |
| 20 | +| `filePosition` | `{ file, line?, column? }` | No | Source file location (clickable in the panel) | |
| 21 | +| `elementPosition` | `{ selector?, boundingBox?, description? }` | No | DOM element position info | |
| 22 | +| `autofix` | `{ type: 'rpc', name: string } \| Function` | No | Autofix action | |
| 23 | +| `notify` | `boolean` | No | Show as a toast notification | |
| 24 | +| `category` | `string` | No | Grouping category (e.g., `'a11y'`, `'lint'`) | |
| 25 | +| `labels` | `string[]` | No | Tags for filtering | |
| 26 | +| `autoDismiss` | `number` | No | Time in ms to auto-dismiss the toast (default: 5000) | |
| 27 | +| `autoDelete` | `number` | No | Time in ms to auto-delete the log entry | |
| 28 | + |
| 29 | +## Server-Side Usage |
| 30 | + |
| 31 | +In your plugin's `devtools.setup`, use `context.logs` to emit log entries: |
| 32 | + |
| 33 | +```ts |
| 34 | +export function myPlugin() { |
| 35 | + return { |
| 36 | + name: 'my-plugin', |
| 37 | + devtools: { |
| 38 | + setup(context) { |
| 39 | + // Simple log |
| 40 | + context.logs.add({ |
| 41 | + message: 'Plugin initialized', |
| 42 | + level: 'info', |
| 43 | + }) |
| 44 | + |
| 45 | + // Warning with file position |
| 46 | + context.logs.add({ |
| 47 | + message: 'Deprecated API usage detected', |
| 48 | + level: 'warn', |
| 49 | + description: 'The `foo()` API is deprecated. Use `bar()` instead.', |
| 50 | + filePosition: { file: 'src/app.ts', line: 42, column: 5 }, |
| 51 | + category: 'lint', |
| 52 | + }) |
| 53 | + |
| 54 | + // Error with stack trace |
| 55 | + context.logs.add({ |
| 56 | + message: 'Build failed', |
| 57 | + level: 'error', |
| 58 | + stacktrace: error.stack, |
| 59 | + category: 'build', |
| 60 | + }) |
| 61 | + |
| 62 | + // Short notification |
| 63 | + context.logs.add({ |
| 64 | + message: 'Configuration reloaded', |
| 65 | + level: 'success', |
| 66 | + notify: true, |
| 67 | + autoDismiss: 3000, |
| 68 | + autoDelete: 10000, |
| 69 | + }) |
| 70 | + }, |
| 71 | + }, |
| 72 | + } |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +The `source` field is automatically set to the plugin name. |
| 77 | + |
| 78 | +## Client-Side Usage |
| 79 | + |
| 80 | +From client-side code (running in the user's browser), emit logs via the RPC client: |
| 81 | + |
| 82 | +```ts |
| 83 | +import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client' |
| 84 | + |
| 85 | +const client = await getDevToolsRpcClient() |
| 86 | + |
| 87 | +await client.call('devtoolskit:internal:logs:add', { |
| 88 | + message: 'Accessibility issue: missing alt text', |
| 89 | + level: 'warn', |
| 90 | + description: 'Images should have alt attributes for screen readers.', |
| 91 | + elementPosition: { |
| 92 | + selector: 'img.hero-image', |
| 93 | + description: 'Hero image in the header', |
| 94 | + }, |
| 95 | + category: 'a11y', |
| 96 | + labels: ['wcag-2.1', 'images'], |
| 97 | +}, 'axe-plugin') |
| 98 | +``` |
| 99 | + |
| 100 | +The second argument to `logs:add` is the `source` identifier. |
| 101 | + |
| 102 | +## Autofix |
| 103 | + |
| 104 | +Autofix actions let users fix issues with a single click. There are two approaches: |
| 105 | + |
| 106 | +### RPC-Based Autofix |
| 107 | + |
| 108 | +Register an RPC function for the fix, then reference it by name: |
| 109 | + |
| 110 | +```ts |
| 111 | +context.rpc.register(defineRpcFunction({ |
| 112 | + name: 'my-plugin:fix-deprecated-api', |
| 113 | + type: 'action', |
| 114 | + setup: () => ({ |
| 115 | + async handler() { |
| 116 | + // Perform the fix |
| 117 | + }, |
| 118 | + }), |
| 119 | +})) |
| 120 | + |
| 121 | +context.logs.add({ |
| 122 | + message: 'Deprecated API usage', |
| 123 | + level: 'warn', |
| 124 | + autofix: { type: 'rpc', name: 'my-plugin:fix-deprecated-api' }, |
| 125 | +}) |
| 126 | +``` |
| 127 | + |
| 128 | +### Function Autofix |
| 129 | + |
| 130 | +For server-side plugins, you can pass a function directly: |
| 131 | + |
| 132 | +```ts |
| 133 | +context.logs.add({ |
| 134 | + message: 'Missing configuration', |
| 135 | + level: 'warn', |
| 136 | + autofix: async () => { |
| 137 | + // Write the config file |
| 138 | + }, |
| 139 | +}) |
| 140 | +``` |
| 141 | + |
| 142 | +## Toast Notifications |
| 143 | + |
| 144 | +Set `notify: true` to show the log entry as a toast notification overlay. Toasts appear regardless of whether the Logs panel is open. |
| 145 | + |
| 146 | +```ts |
| 147 | +context.logs.add({ |
| 148 | + message: 'URL copied to clipboard', |
| 149 | + level: 'success', |
| 150 | + notify: true, |
| 151 | + autoDismiss: 2000, // disappear after 2 seconds |
| 152 | +}) |
| 153 | +``` |
| 154 | + |
| 155 | +The default auto-dismiss time for toasts is 5 seconds. |
| 156 | + |
| 157 | +## Managing Logs |
| 158 | + |
| 159 | +```ts |
| 160 | +// Remove a specific log |
| 161 | +context.logs.remove(entry.id) |
| 162 | + |
| 163 | +// Clear all logs |
| 164 | +context.logs.clear() |
| 165 | +``` |
| 166 | + |
| 167 | +Logs have a maximum capacity of 1000 entries. When the limit is reached, the oldest entries are automatically removed. |
| 168 | + |
| 169 | +## Dock Badge |
| 170 | + |
| 171 | +The Logs dock icon automatically shows a badge with the total log count. The icon is hidden when there are no logs. |
0 commit comments