Structured Diagnostics
ctx.diagnostics is a thin layer over nostics for author-defined coded diagnostics, each with a stable code, docs URL, and structured payload.
| Surface | Purpose | Example |
|---|---|---|
ctx.diagnostics | Coded errors and warnings emitted from node-side code | MYP0001: Plugin foo not configured |
ctx.messages | Free-form, user-facing notifications shown in the Messages panel | 'Audit complete: 3 issues found' |
Shape
interface DevframeDiagnosticsHost {
/** Proxy-backed lookup over every registered code. */
readonly logger: Record<string, DiagnosticHandle>
/** Register additional diagnostic definitions. */
register: (definitions: Record<string, unknown>) => void
/** Build a typed diagnostics object with devframe's ANSI reporter pre-wired. */
defineDiagnostics: typeof defineDiagnostics
}The diagnostics host ships pre-seeded with devframe's DF* codes plus the host framework's own (DTK*, etc.); call register() to add your own.
Register your own codes
export function MyPlugin(): PluginWithDevTools {
return {
name: 'my-plugin',
devtools: {
setup(ctx) {
const myDiagnostics = ctx.diagnostics.defineDiagnostics({
docsBase: 'https://example.com/errors',
codes: {
MYP0001: {
why: (p: { name: string }) => `Plugin "${p.name}" is not configured`,
fix: 'Add the plugin to your `vite.config.ts` and pass an options object.',
},
MYP0002: {
why: 'Cache directory missing; running cold.',
},
},
})
ctx.diagnostics.register(myDiagnostics)
// Emit through the host framework's shared reporter:
myDiagnostics.MYP0002()
},
},
}
}Code conventions
Codes are a 4-letter prefix + 4-digit number (e.g. MYP0001); pick one distinctive enough to avoid collisions.
DF belongs to devframe itself; the @vitejs/devtools packages own DTK, RDDT, and VDT. The prefixes in use are listed in the Node-Side API reference.
A definition takes a why (message) and optional fix (resolution), string or function; docsBase auto-attaches the URL to each diagnostic.
Emit a diagnostic
Each registered code becomes a callable DiagnosticHandle: call it to report, or throw to raise.
// Throw: control flow stops here
throw myDiagnostics.MYP0001({ name: 'foo' })
// Report without throwing (default console method: `warn`)
myDiagnostics.MYP0002()
// Override the console method per call
myDiagnostics.MYP0002({}, { method: 'error' })
// Attach a `cause`: merged into the params object
throw myDiagnostics.MYP0001({ name: 'foo', cause: error })The returned Diagnostic extends Error, so throw narrows following lines as unreachable.
Typed handle reference
ctx.diagnostics.logger is loosely typed over all registered codes; for autocompletion, keep and call the typed result of defineDiagnostics() directly, whose pre-wired ANSI reporter gives it and the lookup identical output.
Document your codes
Pair each code with a documentation page:
docs/errors/
index.md # Table of all codes
MYP0001.md # One page per code
MYP0002.mdEach page covers message, cause, example, and fix; see any DF code page for the template.
When to use what
ctx.diagnostics covers coded, docs-backed conditions, targeting tool authors and CI; ctx.messages covers user-facing UI activity, targeting the human at the panel.