DevTools Plugins
How to create and register custom plugins to extend the DevTools panel with new tabs.
DevTools Plugins
The DevTools panel is extensible — each tab is a plugin, including the three built-in ones. Add new tabs, replace existing ones, or strip the panel down to only what your project needs.
Built-in plugins
The default panels are exported individually so you can import and compose them:
import { SignalsPlugin, ComponentsPlugin, TimelinePlugin } from '@praxisjs/devtools'Customizing which tabs appear
Pass a plugins array to DevTools.init() to control which tabs are shown:
import { DevTools, SignalsPlugin, TimelinePlugin } from '@praxisjs/devtools'
DevTools.init({
plugins: [SignalsPlugin, TimelinePlugin] // no Components tab
})Registering a plugin after init
Use DevTools.registerPlugin() to add a plugin at any point after initialization. If a plugin with the same id is already registered, the call is a no-op.
import { DevTools } from '@praxisjs/devtools'
DevTools.registerPlugin(MyCustomPlugin)Creating a custom plugin
A plugin is a plain object with four fields:
import type { DevtoolsPlugin, Registry } from '@praxisjs/devtools'
import { Component } from '@praxisjs/decorators'
import { StatefulComponent } from '@praxisjs/core'
@Component()
class NetworkTab extends StatefulComponent {
@State() requests: NetworkRequest[] = []
render() {
return (
<div>
{() => this.requests.map(r => (
<div>{r.method} {r.url} — {r.status}</div>
))}
</div>
)
}
}
export const NetworkPlugin: DevtoolsPlugin = {
id: 'network', // unique ID — prevents duplicate registration
label: 'Network', // text shown on the tab
// setup() runs once when the plugin is registered
setup(registry: Registry) {
registry.bus.on('timeline:push', (entry) => {
// react to any timeline event
})
},
// component is rendered inside the tab
component: NetworkTab,
}Interface:
interface DevtoolsPlugin {
id: string
label: string
setup?: (registry: Registry) => void
component: ComponentElement
}Using the Registry
Registry is a singleton that holds all DevTools data. Inside setup() you receive it as an argument. Anywhere else, access it via DevTools.registry:
import { DevTools } from '@praxisjs/devtools'
const registry = DevTools.registry
// Read current data snapshots
registry.getSignals() // SignalEntry[]
registry.getComponents() // ComponentEntry[]
registry.getTimeline() // TimelineEntry[]
// Subscribe to real-time events
registry.bus.on('signal:changed', ({ entry, oldValue }) => { /* ... */ })
registry.bus.on('component:render', (entry) => { /* ... */ })
registry.bus.on('timeline:push', (entry) => { /* ... */ })Available events
| Event | Payload |
|---|---|
signal:registered | SignalEntry |
signal:changed | { entry: SignalEntry, oldValue } |
component:registered | ComponentEntry |
component:render | ComponentEntry |
component:unmount | ComponentEntry |
lifecycle | { componentId, name, hook } |
timeline:push | TimelineEntry |