@polystate/devtools
v0.2.0
Published
Redux DevTools Extension middleware for Polystate
Downloads
102
Maintainers
Readme
@polystate/devtools
Redux DevTools Extension middleware for Polystate with time-travel debugging.
Features
- Redux DevTools Integration: Full support for Redux DevTools Extension
- Time-Travel Debugging: Step through action history
- Action Inspector: View and inspect all actions and state changes
- State Snapshots: Export and import state for debugging
- Action History: Track action sequence and payloads
- Zero Runtime Cost: Only active when DevTools Extension is installed
Installation
npm install @polystate/core @polystate/devtoolsYou also need the Redux DevTools Extension browser extension.
Quick Start
import { createStore } from '@polystate/core';
import { createDevToolsMiddleware } from '@polystate/devtools';
// Create store first (needed so DevTools can call store.setState for time-travel)
const store = createStore(
{ count: 0 },
{
increment: (state) => ({ ...state, count: state.count + 1 }),
},
{
middleware: [
createDevToolsMiddleware(store, {
name: 'CounterStore',
timeTravel: true,
maxAge: 50,
}),
],
}
);
// Now open Redux DevTools to inspect and time-travel!Configuration
Basic Setup
import { createDevToolsMiddleware } from '@polystate/devtools';
const store = createStore(initialState, actions, {
middleware: [createDevToolsMiddleware()],
});With Options
const store = createStore(initialState, actions, {
middleware: [
createDevToolsMiddleware({
// Store name shown in DevTools
name: 'MyAppStore',
// Enable time-travel debugging
timeTravel: true,
// Maximum actions to keep in history
maxAge: 50,
}),
],
});Features
Action Inspection
View all dispatched actions and their payloads:
await store.dispatch('addTodo', { text: 'Learn Polystate' });
// Shows in DevTools:
// {
// type: 'addTodo',
// payload: { text: 'Learn Polystate' },
// timestamp: 1699564032450
// }State Snapshots
Export and import state for debugging:
// Export current state in DevTools
// (Use DevTools UI: Store → Export)
// Import saved state
// (Use DevTools UI: Store → Import State)Time-Travel Debugging
Step forward and backward through action history:
- Open Redux DevTools
- Click on any action in the history
- App state jumps to that point
- Make changes and step forward again
Store Name Configuration
createDevToolsMiddleware({
name: 'UserStore', // Shown in DevTools dropdown
});Multi-Store Setup
Use different names for different stores:
const userStore = createStore(userState, userActions, {
middleware: [createDevToolsMiddleware({ name: 'UserStore' })],
});
const todoStore = createStore(todoState, todoActions, {
middleware: [createDevToolsMiddleware({ name: 'TodoStore' })],
});
const appStore = createStore(appState, appActions, {
middleware: [createDevToolsMiddleware({ name: 'AppStore' })],
});Switch between stores in DevTools dropdown.
Combining with Other Middleware
import { loggerMiddleware, persistMiddleware } from '@polystate/core';
import { createDevToolsMiddleware } from '@polystate/devtools';
const store = createStore(initialState, actions, {
middleware: [
// Logger first (logs complete context)
loggerMiddleware(),
// DevTools for inspection
createDevToolsMiddleware({ name: 'MyStore' }),
// Persist last (fires after other middleware)
persistMiddleware('my-app'),
],
});TypeScript Example
import { createStore } from '@polystate/core';
import { createDevToolsMiddleware } from '@polystate/devtools';
interface AppState {
count: number;
user: { id: number; name: string } | null;
loading: boolean;
}
const store = createStore<AppState>(
{ count: 0, user: null, loading: false },
{
increment: (state) => ({
...state,
count: state.count + 1,
}),
setUser: (state, user: AppState['user']) => ({
...state,
user,
}),
setLoading: (state, loading: boolean) => ({
...state,
loading,
}),
},
{
middleware: [
createDevToolsMiddleware({
name: 'AppStore',
timeTravel: true,
maxAge: 30,
}),
],
}
);
// Dispatch with full type safety
await store.dispatch('increment');
await store.dispatch('setUser', { id: 1, name: 'Alice' });
await store.dispatch('setLoading', false);React Integration
import { createStore } from '@polystate/core';
import { useSelector, useDispatch } from '@polystate/react';
import { createDevToolsMiddleware } from '@polystate/devtools';
const store = createStore(initialState, actions, {
middleware: [createDevToolsMiddleware({ name: 'ReactStore' })],
});
function App() {
const count = useSelector(store, (state) => state.count);
const { dispatch } = useDispatch(store);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch('increment')}>+</button>
</div>
);
}Angular Integration
import { Injectable } from '@angular/core';
import { createStore } from '@polystate/core';
import { PolystateService } from '@polystate/angular';
import { createDevToolsMiddleware } from '@polystate/devtools';
@Injectable({ providedIn: 'root' })
export class CounterService extends PolystateService<{ count: number }> {
private store = createStore(
{ count: 0 },
{ increment: (state) => ({ ...state, count: state.count + 1 }) },
{
middleware: [createDevToolsMiddleware({ name: 'AngularStore' })],
}
);
count = this.select((state) => state.count);
}DevTools Shortcuts
After installing the Redux DevTools Extension:
- Open DevTools: Usually F12 or Cmd+Option+I
- Find Store: Look for the Redux tab in DevTools
- Inspect Action: Click any action to see full details
- Time Travel: Click any action to jump to that state
- Dispatch Action: Use the Actions tab to dispatch manually
- Export State: Use Store → Export State
- Import State: Use Store → Import State
Browser Support
Works in any browser with Redux DevTools Extension installed:
- Chrome
- Firefox
- Edge
- Safari (with extension)
Performance
The middleware has minimal performance impact:
- No overhead if DevTools Extension is not installed
- Efficient action recording
- Configurable history size (default: 50 actions)
- Zero-copy state snapshots
Options Reference
interface DevToolsConfig {
/**
* Store name for DevTools UI
* @default "Polystate Store"
*/
name?: string;
/**
* Enable time-travel debugging
* @default true
*/
timeTravel?: boolean;
/**
* Maximum number of actions to keep in history
* @default 50
*/
maxAge?: number;
}Troubleshooting
DevTools not showing actions
- Install Redux DevTools Extension
- Open DevTools (F12)
- Click "Redux" tab (might be under ">>" icons)
- Make sure Polystate store is selected in dropdown
Actions not time-traveling
Check that timeTravel: true is set in config:
createDevToolsMiddleware({
name: 'MyStore',
timeTravel: true, // ← Add this
});Too many actions in history
Reduce maxAge:
createDevToolsMiddleware({
name: 'MyStore',
maxAge: 20, // Keep only last 20 actions
});API Reference
createDevToolsMiddleware
function createDevToolsMiddleware<T>(config?: DevToolsConfig): Middleware<T>;Creates DevTools middleware for a store.
Parameters:
config- Optional configuration object
Returns: Middleware function
Example:
const middleware = createDevToolsMiddleware({ name: 'AppStore' });connectDevTools
function connectDevTools<T>(store: Store<T>, config?: DevToolsConfig): Store<T>;Connect an existing store to DevTools (if not already connected).
exportStateHistory
function exportStateHistory(store: Store<any>): Array<{ action: string; state: any }>;Export the action/state history.
importStateHistory
function importStateHistory(
store: Store<any>,
history: Array<{ action: string; state: any }>
): void;Import a previously exported history.
Advanced Use Cases
Conditional DevTools
const middleware = [];
if (process.env.NODE_ENV === 'development') {
middleware.push(createDevToolsMiddleware({ name: 'AppStore' }));
}
const store = createStore(initialState, actions, { middleware });Multiple Stores with DevTools
const userStore = createStore(userState, userActions, {
middleware: [createDevToolsMiddleware({ name: 'Users' })],
});
const todoStore = createStore(todoState, todoActions, {
middleware: [createDevToolsMiddleware({ name: 'Todos' })],
});
const settingsStore = createStore(settingsState, settingsActions, {
middleware: [createDevToolsMiddleware({ name: 'Settings' })],
});Switch between them in DevTools to debug each independently.
Contributing
See CONTRIBUTING.md
License
MIT
