Dual output
Every call renders in the browser console (styled) and in the Vite terminal (ANSI), with per-level colors, a tag and the source location.
How it works
MARS TECH
An open-source Vite plugin by MARS TECH. One call prints in the browser console and in the Vite terminal, then disappears from your production build, arguments included.
Every call renders in the browser console (styled) and in the Vite terminal (ANSI), with per-level colors, a tag and the source location.
How it works
Objects, class instances, DOM nodes and Error stacks stay interactive in the browser console, just like console.log.
Live object inspection
In Vue and Nuxt apps, every $debug call also appears in a MARS-TECH timeline layer and inspector inside Vue DevTools, with its payload and source location, once @vue/devtools-api is installed.
Vue DevTools
Every $debug(...) call, method and chained forms included, is rewritten to void 0 at build time and tree-shaken away. Argument expressions never run.
Production builds
The global is installed on the server too, so router guards, store actions and page setup can log during server-side rendering.
Server-side rendering
Scoped loggers with $debug.ns('auth'). Choose what shows at runtime with enable, disable or setLevel, the ?mt-debug= URL parameter, localStorage or the MT_DEBUG variable, with no restart.
Namespaces and filtering
A safety net for a secret that slips into a log: mask tokens, email addresses and your own patterns. A pattern for a secret's shape masks the browser console too; a value you list as a string is masked on the server side and never sent to the page.
Redacting secrets
console-style helpers: assert, time/timeEnd, count, group/groupEnd, table and dir, stripped from production builds like the base calls.
Utility helpers
library.debugBuild ships a dual variant: your library logs in development and is stripped from production builds.
Library authoring
Global types ship in /client for every module-resolution mode, and /eslint provides a flat config that declares the $debug global.
Quickstart
npm install -D @mars-tech/vite-debug-pluginpnpm add -D @mars-tech/vite-debug-pluginyarn add -D @mars-tech/vite-debug-pluginThen register the plugin in vite.config.ts:
// vite.config.ts
import { defineConfig } from "vite";
import mtDebug from "@mars-tech/vite-debug-plugin";
export default defineConfig({
plugins: [mtDebug()],
});Register it unconditionally, in the top-level plugins array: during vite build the plugin is what strips the $debug calls. The Quickstart adds the global type and the ESLint configuration.
The demo below follows a Vue app through three pages. Each line starts with MARS-TECH, the default prefix of this MARS TECH plugin; the prefix option replaces it with your own.
Start the dev server. Start the dev server, open the app and press +1 twice. Every $debug call, first while the app boots and then in the Pinia store action, prints the same line in the browser console and in the Vite terminal: level, tag, message and source location.

$ npm run dev -- --port 4312 --strictPort
MARS-TECH Info [main] - bootstrapping Vue app (src/main.ts:7:0)
MARS-TECH Trace [component/App] - App.vue setup (src/App.vue:4:0)
MARS-TECH Trace [router/beforeEach] - nav: / → / (src/router/index.ts:25:2)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Info [SomeButton/mounted] - SomeButton mounted with variant=primary (src/components/SomeButton.vue:26:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Success [view/Home] - Home mounted (src/views/Home.vue:16:2)
MARS-TECH Info [store/counter] - counter incremented to 1 (src/stores/counter.ts:8:6)
MARS-TECH Info [store/counter] - counter incremented to 2 (src/stores/counter.ts:8:6)Navigate to another page. Open the About page and press Fire delayed (500 ms). Lifecycle hooks, a method called after a timer and a watcher all log through $debug, and each line points to the file, line and column of the call.

MARS-TECH Trace [router/beforeEach] - nav: / → /about (src/router/index.ts:25:2)
MARS-TECH Trace [view/About/lifecycle] - About created (src/views/About.vue:27:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Success [view/About/lifecycle] - About mounted (src/views/About.vue:30:4)
MARS-TECH Info [view/About/method] - delayed fire #1 (src/views/About.vue:40:8)
MARS-TECH Debug [view/About/watch] - delayedCount: 0 → 1 (src/views/About.vue:21:6)Hit an error. Open the Sandbox page and press Throw + log. Leaving About logs its beforeUnmount warning, and the caught error is logged with its stack trace.

MARS-TECH Trace [router/beforeEach] - nav: /about → /sandbox (src/router/index.ts:25:2)
MARS-TECH Warning [view/About/lifecycle] - About beforeUnmount (src/views/About.vue:33:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Trace [view/Sandbox] - Sandbox mounted (src/views/Sandbox.vue:10:2)
MARS-TECH Error [view/Sandbox/handler] - inline throw inside Sandbox handler (src/views/Sandbox.vue:26:4)
Error: inline throw inside Sandbox handler
at throwInline (http://localhost:4312/src/views/Sandbox.vue:38:11)
at callWithErrorHandling (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:1889:17)
at callWithAsyncErrorHandling (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:1896:15)
at HTMLButtonElement.invoker (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:7677:10)The browser console and the Vite terminal print the same lines. In the browser the level is coloured and the source location is in italics; in the terminal the source location is dimmed. A stack trace follows its line in the terminal, and sits in a collapsed “stack” group in the console.
Step 1 of 3 — Start the dev server. Start the dev server, open the app and press +1 twice. Every $debug call, first while the app boots and then in the Pinia store action, prints the same line in the browser console and in the Vite terminal: level, tag, message and source location.
Output:
$ npm run dev -- --port 4312 --strictPort
MARS-TECH Info [main] - bootstrapping Vue app (src/main.ts:7:0)
MARS-TECH Trace [component/App] - App.vue setup (src/App.vue:4:0)
MARS-TECH Trace [router/beforeEach] - nav: / → / (src/router/index.ts:25:2)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Info [SomeButton/mounted] - SomeButton mounted with variant=primary (src/components/SomeButton.vue:26:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Success [view/Home] - Home mounted (src/views/Home.vue:16:2)
MARS-TECH Info [store/counter] - counter incremented to 1 (src/stores/counter.ts:8:6)
MARS-TECH Info [store/counter] - counter incremented to 2 (src/stores/counter.ts:8:6)Step 2 of 3 — Navigate to another page. Open the About page and press Fire delayed (500 ms). Lifecycle hooks, a method called after a timer and a watcher all log through $debug, and each line points to the file, line and column of the call.
Output:
MARS-TECH Trace [router/beforeEach] - nav: / → /about (src/router/index.ts:25:2)
MARS-TECH Trace [view/About/lifecycle] - About created (src/views/About.vue:27:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Success [view/About/lifecycle] - About mounted (src/views/About.vue:30:4)
MARS-TECH Info [view/About/method] - delayed fire #1 (src/views/About.vue:40:8)
MARS-TECH Debug [view/About/watch] - delayedCount: 0 → 1 (src/views/About.vue:21:6)Step 3 of 3 — Hit an error. Open the Sandbox page and press Throw + log. Leaving About logs its beforeUnmount warning, and the caught error is logged with its stack trace.
Output:
MARS-TECH Trace [router/beforeEach] - nav: /about → /sandbox (src/router/index.ts:25:2)
MARS-TECH Warning [view/About/lifecycle] - About beforeUnmount (src/views/About.vue:33:4)
MARS-TECH Trace [shell/mounted] - PageShell mounted (src/components/PageShell.vue:10:2)
MARS-TECH Trace [view/Sandbox] - Sandbox mounted (src/views/Sandbox.vue:10:2)
MARS-TECH Error [view/Sandbox/handler] - inline throw inside Sandbox handler (src/views/Sandbox.vue:26:4)
Error: inline throw inside Sandbox handler
at throwInline (http://localhost:4312/src/views/Sandbox.vue:38:11)
at callWithErrorHandling (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:1889:17)
at callWithAsyncErrorHandling (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:1896:15)
at HTMLButtonElement.invoker (http://localhost:4312/node_modules/.vite/deps/vue.runtime.esm-bundler-BbnC8aGa.js?v=7dcb8c1b:7677:10)The How it works guide walks through the same flow and explains what happens to each call in a production build.