Debug and Logs
SmartCommon provides a colored logging system to facilitate debugging your application.
Enable Debug Mode
In the Provider configuration:
const config = {
debug: true, // Enable logs globally
api: {
debug: true // Enable API-specific logs
}
};
In development, use the environment variable:
const config = {
debug: import.meta.env.DEV // true in dev, false in prod
};
Log Utility
SmartCommon exports a log utility with colored methods:
import { log } from '@cap-rel/smartcommon';
// State logs
log.state('State change:', newState);
log.globalState('Global state updated:', globalState);
// Lifecycle logs
log.effect('useEffect triggered');
log.page('Page loaded: /dashboard');
// Status logs
log.success('Operation successful');
log.error('An error occurred:', error);
log.warning('Warning:', message);
log.info('Information:', data);
// API logs
log.apiLoading('GET', '/api/items');
log.apiSuccess('GET - 200', '/api/items');
log.apiError('GET - 404', '/api/items');
// Database logs
log.db('INSERT:', item);
// Location logs
log.location('Navigating to:', path);
// Custom log
log.custom('MY_TAG', 'purple', 'My message', data);
Log Colors
Each log type has a distinct color in the console:
| Method | Color | Usage |
|---|---|---|
log.state |
Blue | Local state changes |
log.globalState |
Dark Cyan | Global state changes |
log.effect |
Purple | React effects (useEffect) |
log.page |
Orange | Page loading |
log.success |
Green | Successful operations |
log.error |
Red | Errors |
log.warning |
Gold | Warnings |
log.info |
Gray | Information |
log.apiLoading |
Gray | API request in progress |
log.apiSuccess |
Green | Successful API request |
log.apiError |
Red | Failed API request |
log.db |
Navy Blue | IndexedDB operations |
log.location |
Pink | Navigation |
createLogger - Logger with Namespace
For more complex projects, createLogger allows creating a logger with a dedicated namespace. Logs can be filtered by namespace via localStorage.LOG_FILTER.
import { createLogger } from '@cap-rel/smartcommon';
const logger = createLogger('MyModule');
logger.info('Module initialized');
logger.success('Data loaded');
logger.error('Load failed');
logger.warning('Data outdated');
logger.state('Local change:', newState);
logger.globalState('Global change:', data);
logger.effect('useEffect triggered');
logger.page('/dashboard');
logger.db('INSERT', item);
// API (first parameter = dynamic label)
logger.apiLoading('GET /items');
logger.apiSuccess('GET /items', data);
logger.apiError('GET /items', error);
// Custom
logger.custom('PERF', 'orange', 'Rendered in 12ms');
// Groups
logger.group('Initialization');
logger.info('Step 1');
logger.info('Step 2');
logger.groupEnd();
Filter by Namespace
In the browser console:
localStorage.LOG_FILTER = 'MyModule,Auth'; // Show only these namespaces
localStorage.LOG_LEVEL = 'warn'; // debug | info | warn | error
DebugConsole - Built-in Console
The DebugConsole component displays SmartCommon logs directly in the application (floating FAB >_ at bottom left, panel with search/filter toolbar, auto-scrolled colored logs).
Activation
The DebugConsole is mounted by the Provider only if the debug prop is explicitly passed (this is NOT triggered by config.debug, but by the Provider prop itself):
import { Provider } from '@cap-rel/smartcommon';
// Enable only in development mode
<Provider config={config} debug={import.meta.env.DEV}>
<App />
</Provider>
// Always enable
<Provider config={config} debug>
<App />
</Provider>
The config.debug prop remains independent: it controls the verbosity of logs produced by SmartCommon hooks (useStates, useGlobalStates, useApi, etc.), independently from the DebugConsole display.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen |
boolean | false | Console open on startup |
position |
string | "bottom" | Position: "bottom", "top", "left", "right" |
height |
string/number | "40vh" | Console height |
maxLogs |
number | 500 | Maximum number of logs kept |
showFab |
boolean | true | Show floating ">_" button |
Manual Usage (without Provider)
import { DebugConsole } from '@cap-rel/smartcommon';
<DebugConsole defaultOpen={true} position="bottom" maxLogs={200} />
The console can be detached into a separate window via the detach button. Logs are shared between windows via BroadcastChannel.
DebugWarnings - Automatic Breakpoints on React Warnings
The DebugWarnings component intercepts console.error while mounted and triggers debugger as soon as a known React warning is emitted. DevTools (Firefox or Chrome) then pause execution at the warning moment, with the full React stack available to identify the faulty component.
When DevTools are closed, debugger is a no-op: no impact on normal execution.
Activation
Like DebugConsole, DebugWarnings is automatically mounted by the Provider when the debug prop is passed:
<Provider config={config} debug={import.meta.env.DEV}>
<App />
</Provider>
Inactive in production (when debug is false / absent). No additional configuration needed in SmartMaker projects.
Intercepted Warnings
The following patterns trigger an automatic breakpoint:
Received NaN for the value attribute- NaN passed to an<input>value prop on input should not be null-value={null}on inputchanging a controlled input to be uncontrolled-valuechanges from defined toundefinedchanging an uncontrolled input to be controlled- reverseEach child in a list should have a unique "key"- missingkeyin a.map()Maximum update depth exceeded- infinite re-render loopCannot update a component- setState during another component's renderWarning: Failed prop type- violated prop-typesWarning: React does not recognize- non-standard prop passed to DOM
Automatic Diagnosis Before Breakpoint
Before triggering debugger, DebugWarnings displays an orange console.group containing:
- Raw console.error args: raw argument array from React (useful if React includes a
componentStack) - React hint: extraction of "Check the render method of
XXX" when React mentions it - Targeted suspects: for
valueandNaNwarnings, list of fibers wherememoizedProps.valuematches the problem, with React owner and.jsxsource - Full form fibers dump (
console.table): all<input>,<textarea>,<select>in DOM with theirvalue,type,name,owner(parent React component name) andsource(file:line:col if available)
The dump is built by traversing all fiber roots via window.__REACT_DEVTOOLS_GLOBAL_HOOK__. React DevTools must be installed in the browser for the fallback to work completely.
In 90% of cases, the console.table is enough to visually identify which line has an unexpected value (undefined, NaN, null, inconsistent type).
Usage with DevTools
- Open DevTools (
F12) - Console tab: locate the orange
[DebugWarnings]block - Expand the form fibers table -> spot the line with abnormal value -> you have
ownerandsource - If you need the React Call Stack: Debugger tab, execution is paused on
debuggerinDebugWarnings/index.jsx - With source maps enabled (see Vite Configuration for Debug below), clicking on
sourcetakes you directly to the.jsxfile
Manual Usage
If you want to enable only breakpoints without the DebugConsole UI:
import { DebugWarnings } from '@cap-rel/smartcommon';
<App>
{import.meta.env.DEV && <DebugWarnings />}
...
</App>
Or conversely: DebugConsole without breakpoints by mounting it manually instead of using the Provider's debug prop.
Vite Configuration for Debug
SmartCommon's vite.config.js (and any SmartMaker project that produces a lib) is configured for two build modes:
const shouldMinify = process.env.MINIFY !== "false";
export default defineConfig({
build: {
sourcemap: true, // Always generate source maps
minify: shouldMinify, // Minify unless MINIFY=false
lib: { ... }
},
...
});
Two Modes
| Command | Usage | Dist Size |
|---|---|---|
npm run build |
Minified prod build + source map | Normal (~1.2 MB for smartcommon) |
MINIFY=false npm run build |
Readable dev build + source map | Larger (~1.7 MB) but original names preserved |
Why Source Maps
Without source maps, stack traces in Firefox/Chrome display minified names (FM, Nn, ee2...) impossible to interpret.
With source maps:
- Call Stack displays real component names (
Tabbar,SignaturePad,HomePage...) - Clicking a frame takes you directly to the
.jsxsource, exact line DebugWarningspopulates thesourcefield in its dumps (file:line:col)- React DevTools can correctly trace back to application components
In Firefox, if you see the message "Original name mapping is disabled", check "Show original variables" in the Debugger's Scopes panel.
Why Non-Minified Mode (MINIFY=false)
Even with source maps, minified code can resist debugging (local variable names compacted, out-of-order reassignments...). The MINIFY=false mode keeps all original names in the bundle itself, making the debugger much more readable when setting breakpoint in smartcommon source.
Rule: use MINIFY=false only for local debugging, never for publishing.
Working on a local copy of smartcommon
Source maps are already shipped
The published package contains its source maps (dist/*.map, with the source
code embedded). In a project that installs smartcommon from the registry, the
browser's stack traces and debugger therefore already lead back to the
smartcommon src/lib/... files, with nothing to configure. A local copy is
only needed to modify smartcommon (fix in progress, extra logs) or to get
a non-minified bundle.
Wiring the local copy (file:)
Clone smartcommon next to the project, then declare the dependency as a local
path in mobile/package.json:
"dependencies": {
"@cap-rel/smartcommon": "file:../../smartcommon"
}
cd ~/dev/smartcommon
npm install
MINIFY=false npm run build # readable dist/, with source maps
cd ~/dev/myproject/mobile
npm install # node_modules/@cap-rel/smartcommon becomes a link to the copy
The path is relative to mobile/: adjust the number of ../ to your layout.
The project imports the copy's dist/, not its src/: a change is only
visible after a new build.
Dev Loop
- Modify source in
~/dev/smartcommon/src/ cd ~/dev/smartcommon && MINIFY=false npm run build(4-5 seconds)- In consumer project:
rm -rf node_modules/.vite(purge Vite pre-bundle) - Vite automatically reloads on next hit
Projects generated by SmartBoot run scripts/check-smartcommon-fresh.js
before npm run dev and npm run build: if the linked copy's src/ is newer
than its dist/, the command stops instead of serving a stale bundle. Rebuild
smartcommon then.
Variant without touching package.json (symlink)
For a one-off try, without modifying package.json:
cd ~/dev/myproject/mobile
rm -rf node_modules/@cap-rel/smartcommon
ln -s ~/dev/smartcommon node_modules/@cap-rel/smartcommon
The link disappears on the next npm install.
Back to Normal Mode
Put the registry version range back in package.json (for instance
"^1.0.0"), never commit the file: dependency, then:
cd ~/dev/myproject/mobile
npm install @cap-rel/smartcommon@latest
Automatic Logs
When debug: true is enabled, SmartCommon automatically logs:
useStates
const st = useStates({
initialStates: { count: 0 },
debug: true // Enable logs for this hook
});
st.set('count', 1);
// Console: [STATE] SET count => 1
useGlobalStates
const gst = useGlobalStates();
gst.local.set('user', userData);
// Console: [GLOBAL STATE] SET user => {...}
useDb
const db = useDb({
name: 'myApp',
stores: { items: '++id' },
debug: true
});
await db.items.add({ name: 'Item' });
// Console: [DB] CREATE key = 1, item = {...}
useApi
// With api.debug: true in config
api.private.get('items');
// Console: [GET - LOADING] https://api.example.com/items
// Console: [GET - 200] https://api.example.com/items
Conditional Debug
Enable debug only for specific hooks:
// Global debug disabled
const config = { debug: false };
// But debug enabled for a specific hook
const st = useStates({
initialStates: { ... },
debug: true // Override global config
});
Browser Console
SmartCommon logs use CSS styles in the console. To see them correctly:
- Open DevTools (F12)
- Go to "Console" tab
- Ensure "Verbose" filter is enabled
Filter Logs
In the console, use the filter to show only certain types:
- Type
STATEto see state logs - Type
APIto see API logs - Type
DBto see database logs
Best Practices
Disable in Production
const config = {
debug: import.meta.env.DEV,
api: {
debug: import.meta.env.DEV
}
};
Custom Logs in Your Components
import { log } from '@cap-rel/smartcommon';
import { useLibConfig } from '@cap-rel/smartcommon';
const MyComponent = () => {
const { debug } = useLibConfig();
const handleClick = () => {
if (debug) {
log.custom('MY_COMPONENT', 'teal', 'Button clicked');
}
// ...
};
};
Do Not Log Sensitive Data
// Bad
log.info('User logged in:', { password: user.password });
// Good
log.info('User logged in:', { id: user.id, email: user.email });
See Also
- Configuration - Provider Configuration
- Hooks - Hook Documentation