Skip to content

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:

ts
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

OptionTypeDefault
enabledbooleanunset: on in vite dev, off in vite build
levelsMTLevel[]all levels
minLevelMTLevelunset
output{ console?, terminal?, inspect?, devtools?, file?, fileMaxBytes? }every surface on, except file
showSourcebooleantrue
prefixstring'MARS-TECH'
colorsMTColorOverridesunset
globalNamestring'$debug'
prefixFilterstringunset
filterstringunset
showStackbooleanfalse
library{ debugBuild: boolean; brandPrefix?: boolean }unset
redact(string | RegExp)[][]
redactDefaultsbooleanfalse
testfalse | '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. false silences it everywhere; $debug stays 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 a node_modules at or above the Vite root. Without it the integration is left out, and an explicit devtools: true warns 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. true writes to .mt-debug/dev.ndjson under the Vite root; a string is a path, relative to the root or absolute. false, null or unset leaves it off, so file: 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 with terminal: 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 (outside server.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 level warning says so, the terminal gets one warning, and that dev server writes nothing more to the file until it restarts. Infinity lifts 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:

ts
mtDebug({
  colors: {
    error: { label: "Error123" },
  },
});

Resolves to:

ts
{
  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:

ts
// 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/eslint instead of the default export. See Tell ESLint about the global.
  • Vitest: the automatic no-op stub only installs $debug. Set test: false and call installMtDebugStub({ globalName: "myDebug" }) from @mars-tech/vite-debug-plugin/testing in 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 RegExp applies on every surface: the browser console, the dev terminal, SSR output, the log file, Vue DevTools and test: '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 flag y is dropped), and a capture group keeps nothing of its match (the $1 convention 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 a RegExp for 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.
ts
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 configured prefix, globalName, levels and prefixFilter, masked by your redact and redactDefaults. Each Vitest project gets its own logger, built from its own configuration. String redact entries do not reach every Vitest pool: see String redact entries in tests. With enabled: false it falls back to the stub.
  • false registers nothing.

test replaces testStub and testLog. Both still work, with a warning, until 2.0. See Testing.