Skip to content

MARS TECH

@mars-tech/vite-debug-pluginA global $debug() in dev, gone in production

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.

Install

sh
npm install -D @mars-tech/vite-debug-plugin
sh
pnpm add -D @mars-tech/vite-debug-plugin
sh
yarn add -D @mars-tech/vite-debug-plugin

Then register the plugin in vite.config.ts:

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.

How it works

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.

How the plugin works, in 3 steps: the same $debug() calls printed in the browser console and in the Vite terminal.

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.

Browser address:localhost:4312/
Demo Vue app, Home page scrolled down: the end of a Vue DevTools smoke-test card with one button per payload type, then the Pinia counter card showing count: 2 after two clicks on +1.
Browser console — The browser console shows the same lines as the terminal.
Terminal — vite dev
$ 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.

Browser address:localhost:4312/about
Demo Vue app, About page: an Options API showcase card listing lifecycle hooks, a watcher, an async method and a computed label; after a click on Fire delayed (500 ms), the status reads fired ×1.
Browser console — The browser console shows the same lines as the terminal.
Terminal — vite dev
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.

Browser address:localhost:4312/sandbox
Demo Vue app, Sandbox page: a router and error paths card with Throw + log and Navigate to /missing buttons; below them, last error: inline throw inside Sandbox handler.
Browser console — The browser console shows the same lines as the terminal.
Terminal — vite dev
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)
Text version of this animation

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.

  1. 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)
  2. 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)
  3. 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.