Plugin options
Every option at its default value. Options that are unset by default are shown as comments. mtDebug() with no arguments is the same thing:
mtDebug({
// enabled: unset — on in `vite dev`, off in `vite build`
// levels, minLevel: unset — every level is output (same as minLevel: "trace")
// they are alternatives: setting both warns and keeps levels
output: {
console: true,
terminal: true,
inspect: true,
devtools: true, // written out, it warns when @vue/devtools-api is missing
// file: unset — `true` (.mt-debug/dev.ndjson) or a path
fileMaxBytes: 100 * 2 ** 20, // 100 MiB, once `file` is set
},
showSource: true,
prefix: "MARS-TECH",
// colors: unset — e.g. { warning: { label: "Warn" } }
globalName: "$debug",
// prefixFilter: unset — e.g. "-NoisyLib"
// filter: unset — e.g. "cart:*"
showStack: false,
// library: unset — e.g. { debugBuild: true, brandPrefix: true }
redact: [],
redactDefaults: false,
test: "stub",
});Summary
| Option | Type | Default |
|---|---|---|
enabled | boolean | unset: on in vite dev, off in vite build |
levels | MTLevel[] | all levels |
minLevel | MTLevel | unset |
output | { console?, terminal?, inspect?, devtools?, file?, fileMaxBytes? } | every surface on, except file |
showSource | boolean | true |
prefix | string | 'MARS-TECH' |
colors | MTColorOverrides | unset |
globalName | string | '$debug' |
prefixFilter | string | unset |
filter | string | unset |
showStack | boolean | false |
library | { debugBuild: boolean; brandPrefix?: boolean } | unset |
redact | (string | RegExp)[] | [] |
redactDefaults | boolean | false |
test | false | 'stub' | 'log' | 'stub' |
Several options were renamed in 1.0.0. The old names still work, with a warning, until 2.0, but a type-checked vite.config.ts reports them as errors: see Migrating from 0.6. stripInDeps was removed and now strips nothing. The warning it prints ends with "See MIGRATION.md for the migration": the replacement is under stripInDeps in the migration guide.
enabled
Type boolean. Default: unset, which follows the Vite command.
Master switch, keyed off the Vite command: active in vite dev, inert in vite build. It is not keyed off mode, so vite build --mode development stays inert.
false turns the plugin off: no runtime is served or injected, the Vue DevTools API is not pre-bundled, and test: 'log' falls back to the no-op stub. $debug calls are still stripped from your source, so disabled dev code cannot throw. With output.file set, the dev server still keeps that path from the page, since a log an earlier session left may still be on disk.
true does not force the dev runtime into a production build; use library.debugBuild for that. Passing true explicitly changes nothing.
The plugin is also what strips the calls in vite build, so register it unconditionally in the top-level plugins array: see Install and register the plugin. Registered under build.rollupOptions.plugins, or in a Rollup or Rolldown config, it strips the calls as in vite build, without a warning.
levels
Type MTLevel[]. Default: all levels.
Allowlist of the levels that are output. When both levels and minLevel are set, a non-empty levels wins and minLevel is ignored, with a startup warning. An empty levels: [] defers to minLevel, without a warning. The level names are listed in Levels.
minLevel
Type MTLevel. Default: unset.
Threshold: every level at or above it is kept (trace < debug < info < success < warning < error).
output
Type { console?, terminal?, inspect?, devtools?, file?, fileMaxBytes? }. Default: every surface on, except file.
Where output appears. Each key switches one surface, except fileMaxBytes:
console: the browser console.terminal: the Vite terminal. Browser calls are forwarded to it, and SSR and Vite-process calls are printed to it.falsesilences it everywhere;$debugstays defined.inspect: browser only. Also hand the raw payload to the console as a live, inspectable argument. The per-call{ inspect }option overrides it: see Live object inspection.devtools: Vue and Nuxt only. Surface each call in Vue DevTools. Needs the optional peer dependency@vue/devtools-api, installed in anode_modulesat or above the Vite root. Without it the integration is left out, and an explicitdevtools: truewarns at each dev server start: see Vue DevTools.file: also write every call as one NDJSON line (MTLogLine) to a file. Not when your code logs secrets, even redacted: see NDJSON log file.truewrites to.mt-debug/dev.ndjsonunder the Vite root; a string is a path, relative to the root or absolute.false,nullor unset leaves it off, sofile: process.env.MT_LOG === "1"works as a toggle; any other value warns and leaves it off. There is one session per file, written after redaction, and browser calls are included even withterminal: false. The file is not opened under Vitest. The plugin keeps the log from the page, but this is a safety net, not a vault: a log you keep is safer outside the project (outsideserver.fs.allow). Next to some dev tools that read any file for the page, the log stays off. See Keeping the log from the page, and NDJSON log file for the line format.fileMaxBytes: the most the log file holds in one session, in bytes, that last line included. Default: 100 MiB. When the limit is reached, a last line at levelwarningsays so, the terminal gets one warning, and that dev server writes nothing more to the file until it restarts.Infinitylifts the limit;null, like unset, keeps the default; any other value that is not a number over 0 warns and keeps the default. See Sessions and size.
With console, terminal and devtools all off and no file, a no-op $debug is served instead of the runtime, so your calls still do not throw.
output replaces the 0.6 flags browser (now console) and terminal; the flat inspect and devtools keys used during 1.0 development are also still accepted. All four work, with a warning, until 2.0. See Where output appears.
showSource
Type boolean. Default: true.
Show each call's file:line:col: the file relative to the Vite root, with the line and column counted from 1, the same on every surface. The per-call showSource option overrides it call by call.
For a call the dev transform stamps, the location shown is the original source: it is captured at transform time from the combined source map, so it works through .vue single-file component compilation, on both client and SSR (Nuxt included), rather than pointing at the transpiled stack position. A call it cannot stamp (a logger kept from ns() and called later, count(), timeEnd(), assert() and, on the server, group() labels, table() and dir()) takes its position from the runtime stack, which can be a few lines off in compiled code: call $debug(...) directly where the exact line matters. See My log's file:line is a few lines off.
This option was called showSourceLocation before 1.0.0. The old name still works, with a warning, until 2.0.
prefix
Type string. Default: 'MARS-TECH'.
The prefix at the start of every rendered line, for example MARS-TECH Warning [PropsValidator] - Invalid variant "danger". Set it to your application's or library's name. A single call can override it with the per-call prefix option.
colors
Type MTColorOverrides. Default: unset.
Per-level overrides of the label text, the browser CSS color and the terminal color. Any subset of levels, each with any subset of the fields ansi, css and label, is accepted; missing keys fall back to the defaults listed in Levels.
Color override merge
User-supplied colors are deep-merged level by level:
mtDebug({
colors: {
error: { label: "Error123" },
},
});Resolves to:
{
error: { ansi: red, css: '#ef4444', label: 'Error123' },
// other levels untouched
}ansi applies on every terminal surface, with one requirement
Server-side output (SSR renders, $debug called from vite.config.ts or from another plugin) comes from a generated runtime that cannot import your function. So the plugin calls each overridden ansi once, at config time, on a probe string, captures the escape codes it wraps around it, and ships those codes to the runtime. Any plain color wrapper (kolorist, picocolors, chalk, or (s) => "\x1b[35m" + s + "\x1b[39m") is captured exactly. A function that does not return its input verbatim inside the result (one that uppercases, truncates or pads it) has no codes to capture: that level keeps the built-in color on the server, while your function still applies to browser-to-terminal forwarding, which calls it directly. label and css are unaffected everywhere.
globalName
Type string. Default: '$debug'.
Identifier attached to globalThis, for example mtDebug({ globalName: "myDebug" }). The production strip targets the same identifier. It must be a valid JavaScript identifier that is not a reserved word ($debug, myDebug, 日志); anything else, such as a name with a dot, a space or a hyphen, makes mtDebug() throw at startup.
Custom globalName in app code
When you change globalName, the shipped client .d.ts no longer matches. Add your own augmentation:
// src/vite-env.d.ts
import type { MTDebug } from "@mars-tech/vite-debug-plugin/helpers";
declare global {
// eslint-disable-next-line no-var
var myDebug: MTDebug;
}
export {};Declare it as MTDebug
Declare it as MTDebug, not as a bare function. MTDebug is the callable intersected with all 14 methods, so myDebug.ns(...), .table(...) and the variadic overload keep their types; a plain function declaration silently drops every one of them. This mirrors the shipped client.d.ts.
A rename also affects the other tools that know the global by name:
- ESLint: use the named factory
mtDebugFlatConfig({ globalName: "myDebug" })from@mars-tech/vite-debug-plugin/eslintinstead of the default export. See Tell ESLint about the global. - Vitest: the automatic no-op stub only installs
$debug. Settest: falseand callinstallMtDebugStub({ globalName: "myDebug" })from@mars-tech/vite-debug-plugin/testingin a setup file. See Programmatic stub. - With
test: 'log', the custom name is picked up with no extra configuration.
prefixFilter
Type string. Default: unset.
Build-time default prefix filter: mute or isolate logs by their rendered prefix, with a debug-style syntax. It is overridden by the ?mt-debug-prefix= URL parameter and localStorage in the browser, by the MT_DEBUG_PREFIX environment variable on the server, and by $debug.setPrefixFilter(...). See Prefix filtering.
filter
Type string. Default: unset. New in 1.0.0.
Build-time default namespace filter, with the same debug-style syntax as $debug.enable() (cart*, -noisy, auth,cart:*). It is overridden by the ?mt-debug= URL parameter and localStorage in the browser, by MT_DEBUG on the server, and by $debug.enable(pattern) at runtime; $debug.enable(null) returns to it. See Namespaces and runtime filtering.
showStack
Type boolean. Default: false. New in 1.0.0.
Default for the per-call showStack: attach the (redacted) Error stack to every call that carries an Error. { showStack: false } still opts a single call out.
library
Type { debugBuild: boolean; brandPrefix?: boolean }. Default: unset.
Library authoring. debugBuild: true makes vite build emit a dual output: dist/ with every call stripped, and dist/debug/ with the calls kept and a self-installing fallback prepended. brandPrefix: true additionally stamps this library's prefix onto its $debug calls, so they stay branded inside a consuming app; without debugBuild it has no effect, and the plugin warns.
Only the prefix travels: your redact and redactDefaults are not shipped in dist/debug/, so the consuming app's configuration masks your library's output. Never pass a secret to $debug in library code: see Redaction belongs to the consuming app.
library replaces allowDebugBuild and libraryPrefix. Both still work, with a warning, until 2.0. See Library authoring.
redact
Type (string | RegExp)[]. Default: [].
Mask matches with [redacted]. Every rule runs over each string a call hands the plugin (payloads, Error stacks, namespaces and tags, per-call prefixes, helper labels, the source path) and over the printed line, and masks each match whole. Where an entry applies depends on its kind:
- A
RegExpapplies on every surface: the browser console, the dev terminal, SSR output, the log file, Vue DevTools andtest: 'log'. It is sent to the page as written, so it must describe a secret's shape, never contain the secret. It is applied globally (the sticky flagyis dropped), and a capture group keeps nothing of its match (the$1convention of 0.6 is gone): to keep the text in front of a secret, match that text with a lookbehind. - A string matches literally, every occurrence, on the server side only: the dev terminal, the log file, SSR output and
test: 'log'outside Vitest browser mode. It is never sent to the browser, so it does not mask the browser console or Vue DevTools: to mask a value there too, add aRegExpfor its shape. A number is matched as the literal it prints as; an empty or unset value is ignored, and any other value is ignored with a warning.
mtDebug({
redact: [
process.env.DB_PASSWORD ?? "", // string: server side only
/sk_live_[A-Za-z0-9]{8,}/, // RegExp: a secret's shape, masked everywhere
/(?<=x-api-key:\s*)\S+/, // a lookbehind keeps the header name, masks the key
],
});Where the string entries cannot be read, such as in SSR running in a process of its own, $debug prints nothing there rather than print them unmasked, and warns once: see Where string entries cannot reach.
Configuring a RegExp entry or redactDefaults also stops payloads, DOM nodes included, from being passed to the browser console and the Vue DevTools timeline as live objects (per call, { inspect: true } overrides this for the console only), and table() and dir() print the redacted summary. String entries alone do not change this: see Live values in the browser.
Redaction is a safety net, not a vault: it catches a secret that reaches a $debug call by mistake, and does not make logging one safe. See Redacting secrets.
redactDefaults
Type boolean. Default: false.
Also apply a curated set of secret patterns: JWTs, Bearer tokens, Basic credentials after an Authorization: header, emails, Stripe-style keys, and the values of secret keys such as password, token or api_key, as object properties or as [key, value] pairs. Like a RegExp entry, they apply on every surface. The patterns use lookbehinds, so Safari needs version 16.4 or newer to run your dev page. See Default patterns.
test
Type false | 'stub' | 'log'. Default: 'stub'.
What the plugin registers as the first setupFiles entry under Vitest:
'stub'installs a no-op$debug(default global name only).'log'installs a real, config-aware console logger, so$debug(...)calls from components and test files print with your configuredprefix,globalName,levelsandprefixFilter, masked by yourredactandredactDefaults. Each Vitest project gets its own logger, built from its own configuration. Stringredactentries do not reach every Vitest pool: see Stringredactentries in tests. Withenabled: falseit falls back to the stub.falseregisters nothing.
test replaces testStub and testLog. Both still work, with a warning, until 2.0. See Testing.