Skip to content

DevTools Plugins

The DevTools panel is extensible — each tab is a plugin, including the three built-in ones. You can add new tabs, replace existing ones, or strip the panel down to only what you need.

Built-in plugins

The default panels are exported individually:

ts
import { SignalsPlugin, ComponentsPlugin, TimelinePlugin } from '@praxisjs/devtools'

Replacing the default plugins

Pass a plugins array to DevTools.init() to control which tabs are shown:

ts
import { DevTools, SignalsPlugin, TimelinePlugin } from '@praxisjs/devtools'

// Only Signals and Timeline, no Components panel
DevTools.init({
  plugins: [SignalsPlugin, TimelinePlugin]
})

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.

ts
import { DevTools } from '@praxisjs/devtools'

DevTools.registerPlugin(MyCustomPlugin)

Creating a custom plugin

A plugin is a plain object with four fields:

ts
import type { DevtoolsPlugin, Registry } from '@praxisjs/devtools'
import { Component } from '@praxisjs/decorators'
import { StatefulComponent } from '@praxisjs/core'

@Component()
class NetworkTab extends StatefulComponent {
  render() {
    return <div>My network metrics...</div>
  }
}

export const NetworkPlugin: DevtoolsPlugin = {
  id: 'network',       // unique identifier — used to prevent duplicates
  label: 'Network',    // text shown on the tab

  // setup() is called once when the plugin is registered.
  // Use it to subscribe to Registry events or configure side effects.
  setup(registry: Registry) {
    registry.bus.on('timeline:push', (entry) => {
      // react to any timeline event
    })
  },

  // component is the class rendered inside the tab
  component: NetworkTab,
}

Interface:

ts
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:

ts
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 event bus events:

EventPayload
signal:registeredSignalEntry
signal:changed{ entry: SignalEntry, oldValue }
component:registeredComponentEntry
component:renderComponentEntry
component:unmountComponentEntry
lifecycle{ componentId, name, hook }
timeline:pushTimelineEntry

Released under the MIT License.