Reference
nostics
import {
createConsoleReporter,
defineDiagnostics,
defineProdDiagnostics,
Diagnostic,
formatDiagnostic,
} from 'nostics'
defineDiagnostics(options)
const diagnostics = defineDiagnostics({
docsBase: code => `https://nuxt.com/e/${code.replace('NUXT_', '').toLowerCase()}`,
reporters: [createConsoleReporter()],
codes: {
NUXT_B2011: {
why: (p: { src: string, mode: 'client' | 'server' }) => {
const expected = p.mode === 'client' ? 'server' : 'client'
return `Plugin "${p.src}" is ${expected}-only but was registered with mode "${p.mode}".`
},
fix: (p: { mode: 'client' | 'server' }) => {
const expected = p.mode === 'client' ? 'server' : 'client'
return `Rename the file or register it with mode "${expected}".`
},
},
},
})
Options:
| Field | Type | Required | Description |
|---|---|---|---|
codes | Record<string, DiagnosticDefinition> | yes | Code definitions |
docsBase | string | ((code) => string | undefined) | no | Base docs URL or URL resolver |
reporters | DiagnosticReporter[] | no | Reporters called on every diagnostic |
Definition:
interface DiagnosticDefinition<P = any> {
why: string | ((params: P) => string)
fix?: string | ((params: P) => string)
docs?: string | false
}
Call-site fields:
interface DiagnosticCallParams {
cause?: unknown
sources?: string[]
}
defineProdDiagnostics(options?)
Lean production counterpart to defineDiagnostics. Returns a Proxy that builds a minimal Diagnostic for any accessed code: the code becomes the instance name, docs is derived from docsBase, and the message (why) points to the docs URL when one exists (empty otherwise, so the thrown header is just the code). It carries no catalog text, so it stays tiny in a bundle.
const diagnostics = defineProdDiagnostics({
docsBase: code => `https://nuxt.com/e/${code.replace('NUXT_', '').toLowerCase()}`,
})
throw diagnostics.NUXT_B2011() // Error: NUXT_B2011, docs derived from docsBase
Options:
| Field | Type | Required | Description |
|---|---|---|---|
docsBase | string | ((code) => string | undefined) | no | Base docs URL or URL resolver, identical to defineDiagnostics |
reporters | DiagnosticReporter[] | no | Reporters called on every diagnostic. Omitted by default in production builds |
Select it in production with a process.env.NODE_ENV ternary so bundlers drop the full catalog. See Production builds.
Diagnostic
class Diagnostic extends Error {
name: string
message: string
get why(): string
fix?: string
docs?: string
sources?: string[]
cause?: unknown
toJSON(): object
}
name is the code. message and why are the resolved explanation. toJSON() returns name, why, fix, docs, sources, cause, and stack.
When you call JSON.stringify(diagnostic), fields whose value is undefined are omitted from the JSON output.
formatDiagnostic(diagnostic)
Renders plain multiline text.
[NUXT_B2011] Plugin `./runtime/analytics.server.ts` is server-only but was registered with mode `client`.
├▶ fix: Rename the file or register it with mode `server`.
├▶ sources: modules/analytics.ts:18:5
╰▶ see: https://nuxt.com/e/b2011
createConsoleReporter
function createConsoleReporter(options?: {
method?: 'log' | 'error' | 'warn' // default 'warn'
formatter?: (diagnostic: Diagnostic) => string // default formatDiagnostic
}): DiagnosticReporter<{ method?: 'log' | 'error' | 'warn' }>
Builds a console reporter. createConsoleReporter() uses console.warn and formatDiagnostic; method is overridable per call.
Reporters
nostics/reporters/node
import { createFileReporter } from 'nostics/reporters/node'
function createFileReporter(options?: {
logFile?: string
excludeStackFrames?: readonly RegExp[]
}): DiagnosticReporter
Appends one JSON line per diagnostic. Default file: .nostics.log. excludeStackFrames defaults to [/\/node_modules\//i]; pass [] to keep every frame.
nostics/reporters/fetch
import { createFetchReporter } from 'nostics/reporters/fetch'
function createFetchReporter(url: string): DiagnosticReporter
POSTs JSON.stringify(diagnostic) to url with Content-Type: application/json. Fetch failures are swallowed.
nostics/reporters/dev
import { createDevReporter } from 'nostics/reporters/dev'
createDevReporter() builds a reporter that sends diagnostic.toJSON() over import.meta.hot.send('nostics:report', payload). Outside Vite, it warns and does nothing else.
Formatters
nostics/formatters/ansi
import { ansiFormatter } from 'nostics/formatters/ansi'
function ansiFormatter(colors: Colors): (diagnostic: Diagnostic) => string
interface Colors {
red: (s: string) => string
yellow: (s: string) => string
cyan: (s: string) => string
gray: (s: string) => string
bold: (s: string) => string
dim: (s: string) => string
}
nostics/formatters/json
import { jsonFormatter } from 'nostics/formatters/json'
const jsonFormatter: (diagnostic: Diagnostic) => string
Calls JSON.stringify(diagnostic).
Plugins
The build-time plugins ship in the separate @nostics/unplugin package:
pnpm add -D @nostics/unplugin
@nostics/unplugin/strip-transform
import { nosticsStrip } from '@nostics/unplugin/strip-transform'
Build-time plugin that marks defineDiagnostics() calls as pure and guards report-only diagnostic expression statements with process.env.NODE_ENV !== "production".
nosticsStrip.vite({
packageName: 'nostics',
})
Options:
| Field | Default | Description |
|---|---|---|
packageName | 'nostics' | Package name to detect imports from |
@nostics/unplugin/dev-server-collector
import { nosticsCollector } from '@nostics/unplugin/dev-server-collector'
Vite dev-server plugin that listens for nostics:report events and appends diagnostics to a local file.
nosticsCollector.vite({
logFile: '.nostics.log',
debug: false,
excludeStackFrames: [/\/node_modules\//],
})
Options:
| Field | Default | Description |
|---|---|---|
logFile | '.nostics.log' | Output file |
debug | !!process.env.DEBUG | Log collector activity |
excludeStackFrames | [/\/node_modules\//i] | Remove matching stack frames before writing. Pass [] to keep every frame |
Only the Vite adapter is meaningful for nosticsCollector.