nano-debugger
v0.1.1
Published
Visual debugger for nanostores - Framework-agnostic devtools panel
Downloads
48
Maintainers
Readme
nano-debugger
A visual debugger for nanostores, built on top of @nanostores/logger. It shows the same values you’d otherwise see in the browser console, but inside a panel.
Features
- Framework Agnostic - Works with React, Vue, Svelte, vanilla JS, and any other framework
- Logger-aligned - Uses
@nanostores/loggersemantics for mount/unmount/change/action events - Real-time Monitoring - Track store changes as they happen
- Manual Registration - Register stores by name (logger-style)
- Opt-in - Initialize explicitly via
enabled: trueand guard in your app - Shadow DOM - Isolated styles that won't conflict with your app
Installation
pnpm add nano-debugger nanostoresQuick Start
Vanilla JS / TypeScript
import { createNanostoresDebugger } from 'nano-debugger';
// Initialize the debugger (development only)
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
}With Configuration
import { createNanostoresDebugger } from 'nano-debugger';
if (import.meta.env.DEV) {
createNanostoresDebugger({
enabled: true,
defaultOpen: false, // Whether the panel is open by default
loggerOptions: {
messages: { action: false }
}
});
}Manual Store Registration
By default, stores need to be manually registered. Use the debugStore helper to register your stores with friendly names:
import { atom, map, computed } from 'nanostores';
import { debugStore } from 'nano-debugger';
// Atom store
const $counter = atom(0);
debugStore('Counter', $counter, 'atom');
// Map store
const $user = map({ name: 'Alice', age: 30 });
debugStore('User Profile', $user, 'map');
// Computed store
const $isAdult = computed($user, (user) => user.age >= 18);
debugStore('Is Adult (Computed)', $isAdult, 'computed');
// Or let the debugger infer the type
debugStore('Is Adult (Computed)', $isAdult);Logger-style Registration
Register multiple stores at once (like @nanostores/logger):
import { debugStores } from 'nano-debugger';
import { $profile, $users } from './stores';
debugStores({
Profile: $profile,
Users: $users
});Note: call createNanostoresDebugger({ enabled: true }) first. Unlike debugStore, debugStores does not queue registrations before the debugger is initialized.
Usage with Frameworks
React
// main.tsx
import { createNanostoresDebugger } from 'nano-debugger';
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
}
// Your stores
import { atom } from 'nanostores';
import { debugStore } from 'nano-debugger';
export const $counter = atom(0);
debugStore('Counter', $counter, 'atom');
// Component
import { useStore } from '@nanostores/react';
function Counter() {
const counter = useStore($counter);
return (
<button onClick={() => $counter.set(counter + 1)}>
Count: {counter}
</button>
);
}Vue
// main.ts
import { createNanostoresDebugger } from 'nano-debugger';
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
}
// Your stores
import { atom } from 'nanostores';
import { debugStore } from 'nano-debugger';
export const $counter = atom(0);
debugStore('Counter', $counter, 'atom');<!-- Component.vue -->
<script setup>
import { useStore } from '@nanostores/vue';
import { $counter } from './stores';
const counter = useStore($counter);
</script>
<template>
<button @click="$counter.set(counter + 1)">
Count: {{ counter }}
</button>
</template>Svelte
// main.ts
import { createNanostoresDebugger } from 'nano-debugger';
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
}
// Your stores
import { atom } from 'nanostores';
import { debugStore } from 'nano-debugger';
export const counter = atom(0);
debugStore('Counter', counter, 'atom');<!-- Component.svelte -->
<script>
import { counter } from './stores';
</script>
<button on:click={() => counter.set($counter + 1)}>
Count: {$counter}
</button>Astro
---
// src/pages/index.astro
---
<script>
import { createNanostoresDebugger, debugStore } from 'nano-debugger';
import { $count } from '../stores/counter';
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
debugStore('Shared Counter', $count, 'atom');
}
</script>API Reference
createNanostoresDebugger(config?)
Initialize the debugger. Returns the debugger instance or null when disabled.
Parameters:
config(optional): Configuration objectenabled?: boolean- Required. Set totrueto initialize the debuggerdefaultOpen?: boolean- Whether the panel is open by default (default:false)loggerOptions?: LoggerOptions- Pass-through options for@nanostores/logger(messages,ignoreActions)
Returns: DebuggerInstance | null
debugStore(name, store, type?)
Manually register a store with the debugger.
Parameters:
name: string- Friendly name for the storestore: any- The nanostore instance (atom, map, or computed)type?: 'atom' | 'map' | 'computed'- Optional store type (inferred if omitted)
Example:
import { atom, map, computed } from 'nanostores';
import { debugStore } from 'nano-debugger';
const $counter = atom(0);
debugStore('Counter', $counter, 'atom');
const $user = map({ name: 'Alice' });
debugStore('User', $user, 'map');
const $doubled = computed($counter, (count) => count * 2);
debugStore('Doubled', $doubled, 'computed');debugStores(stores)
Register multiple stores at once (logger-style).
Parameters:
stores: Record<string, any>- Map of store name to store instance
Example:
import { debugStores } from 'nano-debugger';
import { $profile, $users } from './stores';
debugStores({
Profile: $profile,
Users: $users
});getDebuggerInstance()
Get the current debugger instance.
Returns: DebuggerInstance | null
DebuggerInstance
The debugger instance has the following methods:
open()- Open the debugger panelclose()- Close the debugger paneltoggle()- Toggle the debugger panel open/closeddestroy()- Destroy the debugger and clean up
Example:
const debugger = createNanostoresDebugger({ enabled: true });
// Open programmatically
debugger?.open();
// Close programmatically
debugger?.close();
// Clean up
debugger?.destroy();UI Features
Toggle Button
A floating button that shows the store count and opens/closes the panel.
Store List View
- Shows store type (atom, map, computed)
- Shows mount status (mounted / unmounted)
- Displays current value preview
Development
# Clone the repository
git clone https://github.com/ninuzdellalb/nanostores-debugger.git
# Install dependencies
pnpm install
# Build the library
pnpm build
# Install example deps
pnpm dev:install
# Run the example
pnpm devProduction Builds
This package does not auto-detect dev/prod inside bundled libraries.
Guard initialization in your app and pass enabled: true only in development.
For example:
Vite (default)
if (import.meta.env.DEV) {
createNanostoresDebugger({ enabled: true });
}Webpack
if (process.env.NODE_ENV === 'development') {
createNanostoresDebugger({ enabled: true });
}The debugger will be completely tree-shaken from production builds when wrapped in these conditions.
Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
Requires ES6+ support and Shadow DOM.
TypeScript
Fully typed with TypeScript. No additional @types package needed.
import type { DebuggerConfig, DebuggerInstance, StoreInfo } from 'nano-debugger';
import type { LoggerOptions } from '@nanostores/logger';License
MIT
Contributing
Contributions are welcome. Open a PR with a clear description of the change.
Credits
Inspired by React Query DevTools and built for the amazing nanostores library.
