npm library
Tag your logs per file, filter them in real time, and watch them stream into a sleek in-page panel — without opening DevTools.
Demo
How it works
Call initConsole() at your entry point. The panel mounts and starts listening immediately.
Call useLogger('MyScope') per file. Every log is tagged with that scope automatically.
Toggle scopes and levels. Logs still appear in DevTools too — nothing changes about your existing workflow.
In production, everything is replaced with no-ops via export conditions. No tree-shaking config needed.
Usage
import { initConsole } from '@bajzik/scoped-console' initConsole()
import { useLogger } from '@bajzik/scoped-console' const logger = useLogger('UserProfile') async function fetchUser(id: string) { logger.info('fetching', id) try { await userStore.fetch(id) logger.log('done') } catch (err) { logger.error('failed', err) } }
import { useLogger } from '@bajzik/scoped-console' const logger = useLogger('OrderView') export default { mounted() { logger.log('mounted') }, methods: { async fetchOrder(id) { logger.info('fetching', id) try { const order = await this.$http.get(`/orders/${id}`) logger.log('loaded', order) } catch (err) { logger.error('failed', err) } } } }
import { useLogger } from '@bajzik/scoped-console' const logger = useLogger('service:api') export async function getUser(id) { logger.info('GET /users/', id) const res = await fetch(`/api/users/${id}`) if (!res.ok) { logger.error('request failed', res.status) throw new Error('fetch failed') } return res.json() }
The panel
Renders at the bottom of the page in a shadow DOM container. Toggle scopes and levels interactively. All state persists to localStorage.
Features
Each scope gets a unique consistent color derived from its name — visible on tabs and log entries.
Exact file, line, and column via stack trace parsing. No guessing where a log came from.
Objects and arrays render with colored keys, strings, numbers, and booleans — DevTools-style.
Drag dividers to resize time, level, scope, and file columns. Sizes persist to localStorage.
The panel is encapsulated in shadow DOM so your app styles never bleed into it — or vice versa.
Export conditions stub everything out in production. Works in Vite, webpack 5, Rollup, esbuild.
API
| function | description |
|---|---|
| initConsole(config?) | Initialize the library. Call once before anything else. config.mount defaults to 'body'. |
| useLogger(scope) | Returns a scoped logger with log, info, warn, error, debug methods. Re-asserts scope before every call — safe in async contexts. |
| destroyConsole() | Restore the original console and remove the panel from the DOM. |
Changelog
defineScope with useLogger — fixes async timing issues in reactive frameworks