|
| 1 | +# Logs & Notifications |
| 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 a11y checks or similar tools on the client side, report warnings with element positions |
| 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 | +| `notify` | `boolean` | No | Show as a toast notification | |
| 23 | +| `category` | `string` | No | Grouping category (e.g., `'a11y'`, `'lint'`) | |
| 24 | +| `labels` | `string[]` | No | Tags for filtering | |
| 25 | +| `autoDismiss` | `number` | No | Time in ms to auto-dismiss the toast (default: 5000) | |
| 26 | +| `autoDelete` | `number` | No | Time in ms to auto-delete the log entry | |
| 27 | +| `status` | `'loading' \| 'idle'` | No | Status indicator (shows spinner when `'loading'`) | |
| 28 | +| `id` | `string` | No | Explicit id for deduplication — re-adding with the same id updates the existing entry | |
| 29 | + |
| 30 | +The `source` field is automatically set to `'server'` or `'client'` depending on where the log was emitted. |
| 31 | + |
| 32 | +## Usage |
| 33 | + |
| 34 | +Both server-side and client-side share the same `context.logs` API. All methods return Promises, but you don't need to `await` them for fire-and-forget usage. |
| 35 | + |
| 36 | +### Fire-and-Forget |
| 37 | + |
| 38 | +```ts |
| 39 | +// No await needed — just emit the log |
| 40 | +context.logs.add({ |
| 41 | + message: 'Plugin initialized', |
| 42 | + level: 'info', |
| 43 | +}) |
| 44 | +``` |
| 45 | + |
| 46 | +### With Handle |
| 47 | + |
| 48 | +`await` the `add()` call to get a `DevToolsLogHandle` for subsequent updates: |
| 49 | + |
| 50 | +```ts |
| 51 | +// Await to get a handle for later updates |
| 52 | +const handle = await context.logs.add({ |
| 53 | + id: 'my-build', |
| 54 | + message: 'Building...', |
| 55 | + level: 'info', |
| 56 | + status: 'loading', |
| 57 | +}) |
| 58 | + |
| 59 | +// Later, update via the handle |
| 60 | +await handle.update({ |
| 61 | + message: 'Build complete', |
| 62 | + level: 'success', |
| 63 | + status: 'idle', |
| 64 | +}) |
| 65 | + |
| 66 | +// Or dismiss it |
| 67 | +await handle.dismiss() |
| 68 | +``` |
| 69 | + |
| 70 | +### Server-Side Example |
| 71 | + |
| 72 | +```ts |
| 73 | +export function myPlugin() { |
| 74 | + return { |
| 75 | + name: 'my-plugin', |
| 76 | + devtools: { |
| 77 | + setup(context) { |
| 78 | + // Fire-and-forget |
| 79 | + context.logs.add({ |
| 80 | + message: 'Plugin initialized', |
| 81 | + level: 'info', |
| 82 | + }) |
| 83 | + }, |
| 84 | + }, |
| 85 | + } |
| 86 | +} |
| 87 | +``` |
| 88 | + |
| 89 | +### Client-Side Example |
| 90 | + |
| 91 | +```ts |
| 92 | +import type { DockClientScriptContext } from '@vitejs/devtools-kit/client' |
| 93 | + |
| 94 | +export default async function (context: DockClientScriptContext) { |
| 95 | + // Await to get the handle |
| 96 | + const log = await context.logs.add({ |
| 97 | + message: 'Running audit...', |
| 98 | + level: 'info', |
| 99 | + status: 'loading', |
| 100 | + notify: true, |
| 101 | + }) |
| 102 | + |
| 103 | + // ... do work ... |
| 104 | + |
| 105 | + // Update via handle — can also be fire-and-forget |
| 106 | + log.update({ |
| 107 | + message: 'Audit complete — 3 issues found', |
| 108 | + level: 'warn', |
| 109 | + status: 'idle', |
| 110 | + }) |
| 111 | +} |
| 112 | +``` |
| 113 | + |
| 114 | +## Log Handle |
| 115 | + |
| 116 | +`context.logs.add()` returns a `Promise<DevToolsLogHandle>` with: |
| 117 | + |
| 118 | +| Property/Method | Description | |
| 119 | +|-----------------|-------------| |
| 120 | +| `handle.id` | The log entry id | |
| 121 | +| `handle.entry` | The current `DevToolsLogEntry` data | |
| 122 | +| `handle.update(patch)` | Partially update the log entry (returns `Promise`) | |
| 123 | +| `handle.dismiss()` | Remove the log entry (returns `Promise`) | |
| 124 | + |
| 125 | +Both `handle.update()` and `handle.dismiss()` return Promises but can be used without `await` for fire-and-forget. |
| 126 | + |
| 127 | +## Deduplication |
| 128 | + |
| 129 | +When you call `add()` with an explicit `id` that already exists, the existing entry is **updated** instead of duplicated. This is useful for logs that represent ongoing operations: |
| 130 | + |
| 131 | +```ts |
| 132 | +// First call creates the entry |
| 133 | +context.logs.add({ id: 'my-scan', message: 'Scanning...', level: 'info', status: 'loading' }) |
| 134 | + |
| 135 | +// Second call with same id updates it |
| 136 | +context.logs.add({ id: 'my-scan', message: 'Scan complete', level: 'success', status: 'idle' }) |
| 137 | +``` |
| 138 | + |
| 139 | +## Toast Notifications |
| 140 | + |
| 141 | +Set `notify: true` to show the log entry as a toast notification overlay. Toasts appear regardless of whether the Logs panel is open. |
| 142 | + |
| 143 | +```ts |
| 144 | +context.logs.add({ |
| 145 | + message: 'URL copied to clipboard', |
| 146 | + level: 'success', |
| 147 | + notify: true, |
| 148 | + autoDismiss: 2000, // disappear after 2 seconds |
| 149 | +}) |
| 150 | +``` |
| 151 | + |
| 152 | +The default auto-dismiss time for toasts is 5 seconds. |
| 153 | + |
| 154 | +## Managing Logs |
| 155 | + |
| 156 | +```ts |
| 157 | +// Remove a specific log by id |
| 158 | +context.logs.remove(entryId) |
| 159 | + |
| 160 | +// Clear all logs |
| 161 | +context.logs.clear() |
| 162 | +``` |
| 163 | + |
| 164 | +Logs have a maximum capacity of 1000 entries. When the limit is reached, the oldest entries are automatically removed. |
| 165 | + |
| 166 | +## Dock Badge |
| 167 | + |
| 168 | +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