@maxax/x-plugins-mitt
v1.0.1
Published
A lightweight event bus wrapper based on mitt for Maxax projects
Maintainers
Readme
@maxax/x-plugins-mitt
A lightweight event bus wrapper based on mitt for Maxax projects. This package provides a powerful event bus system designed for micro-frontend architectures, supporting communication between master and slave applications.
Features
- Lightweight: Built on top of mitt, minimal footprint
- Type-safe: Full TypeScript support with generic types
- Micro-frontend Ready: Built-in support for master-slave application communication
- Flexible: Multiple ways to get event bus instances (singleton, factory)
- Powerful: Supports wildcards, once events, and comprehensive event management
Installation
npm install @maxax/x-plugins-mitt mitt
# or
pnpm add @maxax/x-plugins-mitt mitt
# or
yarn add @maxax/x-plugins-mitt mittQuick Start
Basic Usage
import { getEventBus, createEventBus } from '@maxax/x-plugins-mitt'
// Option 1: Use singleton instance
const eventBus = getEventBus()
// Option 2: Create a new instance
const eventBus = createEventBus()
// Define event types
interface MyEvents {
userLoggedIn: { userId: string; username: string }
notification: { message: string; type: 'info' | 'warning' | 'error' }
[key: string]: any
}
// Subscribe to events
eventBus.on('userLoggedIn', (data) => {
console.log(`User ${data.username} logged in with ID: ${data.userId}`)
})
// Publish events
eventBus.emit('userLoggedIn', { userId: '123', username: 'john' })
// Unsubscribe
const unsubscribe = eventBus.on('notification', (data) => {
console.log('Notification:', data.message)
})
unsubscribe()Manager Usage (Micro-frontend)
For micro-frontend architectures, use the MaxEventBusManager to coordinate events between master and slave applications:
import { getMaxEventBusManager } from '@maxax/x-plugins-mitt'
// Get manager instance
const manager = getMaxEventBusManager()
// ============ Master Application ============
// Listen for events from any slave application
manager.onAnySlave('dataUpdated', (data, appName) => {
console.log(`Received data update from ${appName}:`, data)
})
// Broadcast to all applications
manager.broadcast('globalNotification', {
message: 'System will restart in 5 minutes',
severity: 'warning'
})
// ============ Slave Application ============
// Send event to master
manager.toMaster('slaveReady', { appName: 'dashboard', timestamp: Date.now() })
// Send event to specific slave
manager.toSlave('orderApp', 'newOrder', { orderId: 'ORD-001', amount: 99.99 })
// Listen to master events
manager.onMaster('configChanged', (data) => {
console.log('New configuration:', data)
})API Reference
MaxEventBus
The core event bus class.
Constructor
constructor()Creates a new event bus instance.
Methods
emit
emit<Key extends keyof MaxEvents>(type: Key, data: MaxEvents[Key]): voidPublishes an event with data.
eventBus.emit('userCreated', { userId: '123', email: '[email protected]' })emitWithout
emitWithout<Key extends keyof MaxEvents>(type: ...): voidPublishes an event without data.
on
on<Key extends keyof MaxEvents>(event: Key, callback: Handler<MaxEvents[Key]>): () => voidSubscribes to an event. Returns an unsubscribe function.
const unsubscribe = eventBus.on('message', (data) => {
console.log('Received message:', data)
})
// Later, unsubscribe
unsubscribe()once
once<Key extends keyof MaxEvents>(event: Key, callback: Handler<MaxEvents[Key]>): () => voidSubscribes to an event that only fires once.
eventBus.once('initComplete', () => {
console.log('Initialization complete!')
})onBoth
onBoth(handler: WildcardHandler<MaxEvents>): () => voidSubscribes to all events (wildcard).
eventBus.onBoth((event, data) => {
console.log(`Event "${event}" fired with data:`, data)
})off
off<Key extends keyof MaxEvents>(event: Key, callback?: Handler<MaxEvents[Key]>): voidUnsubscribes from an event. If no callback provided, removes all listeners for that event.
clear
clear(): voidRemoves all event listeners.
Factory Functions
// Get or create singleton instance
function getEventBus(): MaxEventBus
// Create a new instance
function createEventBus(): MaxEventBus
// Reset singleton instance
function resetEventBus(): voidMaxEventBusManager
Event bus manager for micro-frontend architectures.
Methods
getMasterBus
getMasterBus(): MaxEventBusReturns the master application event bus.
registerSlaveBus
registerSlaveBus(appName: string, slaveEventBus: MaxEventBus): voidRegisters a slave application event bus.
unregisterSlaveBus
unregisterSlaveBus(appName: string): voidUnregisters a slave application.
broadcast
broadcast<K extends string>(event: K, data?: any): voidBroadcasts an event to all applications (master + all slaves).
toMaster
toMaster<K extends string>(event: K, data?: any): voidSends an event to the master application.
toSlave
toSlave<K extends string>(appName: string, event: K, data?: any): voidSends an event to a specific slave application.
toSlaves
toSlaves<K extends string>(appNames: string[], event: K, data?: any): voidSends an event to multiple slave applications.
onMaster
onMaster<K extends string>(event: K, callback: (data: any) => void): () => voidListens to events from the master application.
onSlave
onSlave<K extends string>(appName: string, event: K, callback: (data: any) => void): () => voidListens to events from a specific slave application.
onAnySlave
onAnySlave<K extends string>(event: K, callback: (data: any, appName: string) => void): () => voidListens to events from any slave application. Callback receives the data and app name.
getRegisteredApps
getRegisteredApps(): string[]Returns a list of registered slave application names.
destroy
destroy(): voidDestroys the manager and all associated event buses.
Advanced Examples
Complete Micro-frontend Setup
// master.ts - Main application
import { getMaxEventBusManager, createEventBus } from '@maxax/x-plugins-mitt'
const masterBus = getMaxEventBusManager()
// Listen for all slave events
masterBus.onAnySlave('*', (event, data, appName) => {
console.log(`[${appName}] ${event}:`, data)
})
// Send configuration to all apps
masterBus.broadcast('configUpdate', {
theme: 'dark',
language: 'en',
apiUrl: 'https://api.example.com'
})
// Handle slave registration
masterBus.onSlave('reactApp', 'register', (data) => {
console.log('React app registered:', data)
})
// -------------------------------------------------
// slave-react.ts - React micro-frontend
import { createEventBus, getMaxEventBusManager } from '@maxax/x-plugins-mitt'
const slaveBus = createEventBus()
const manager = getMaxEventBusManager()
// Register with master
manager.registerSlaveBus('reactApp', slaveBus)
// Notify master we're ready
manager.toMaster('register', {
name: 'React Dashboard',
version: '1.0.0',
components: ['Chart', 'Table', 'Form']
})
// Listen for config changes
manager.onMaster('configUpdate', (config) => {
applyConfig(config)
})
// Broadcast events to other apps
slaveBus.emit('dataLoaded', { count: 42, timestamp: Date.now() })
// -------------------------------------------------
// slave-vue.ts - Vue micro-frontend
import { createEventBus, getMaxEventBusManager } from '@maxax/x-plugins-mitt'
const slaveBus = createEventBus()
const manager = getMaxEventBusManager()
// Register with master
manager.registerSlaveBus('vueApp', slaveBus)
// Listen to all events from React app
manager.onSlave('reactApp', 'dataLoaded', (data) => {
console.log('React app loaded data:', data)
})
// Send events to master
manager.toMaster('vueReady', { name: 'Vue Admin', status: 'active' })Using with React
// useEventBus.ts
import { useEffect, useCallback } from 'react'
import { getEventBus } from '@maxax/x-plugins-mitt'
export function useEventBus<EventMap extends Record<string, any>>() {
const eventBus = getEventBus()
const subscribe = useCallback(<K extends keyof EventMap>(
event: K,
callback: (data: EventMap[K]) => void
) => {
return eventBus.on(event, callback)
}, [eventBus])
const publish = useCallback(<K extends keyof EventMap>(
event: K,
data: EventMap[K]
) => {
eventBus.emit(event, data)
}, [eventBus])
return { subscribe, publish }
}
// Component.tsx
import { useEventBus } from './useEventBus'
interface MyEvents {
counterUpdate: { count: number }
reset: void
}
function Counter() {
const { subscribe, publish } = useEventBus<MyEvents>()
const [count, setCount] = useState(0)
useEffect(() => {
return subscribe('counterUpdate', ({ count }) => {
setCount(count)
})
}, [subscribe])
const increment = () => {
publish('counterUpdate', { count: count + 1 })
}
return <button onClick={increment}>{count}</button>
}Using with Vue 3 Composable
// composables/useEventBus.ts
import { onUnmounted } from 'vue'
import { getEventBus } from '@maxax/x-plugins-mitt'
export function useEventBus<EventMap extends Record<string, any>>() {
const eventBus = getEventBus()
const on = <K extends keyof EventMap>(
event: K,
callback: (data: EventMap[K]) => void
) => {
const unsubscribe = eventBus.on(event, callback)
onUnmounted(unsubscribe)
return unsubscribe
}
const emit = <K extends keyof EventMap>(
event: K,
data: EventMap[K]
) => {
eventBus.emit(event, data)
}
return { on, emit }
}TypeScript Support
This library is written in TypeScript and provides full type safety:
import { createEventBus } from '@maxax/x-plugins-mitt'
// Define your events
interface AppEvents {
userLogin: { userId: string; username: string }
userLogout: void
notification: { message: string; type: string }
[key: string]: any
}
// Create typed event bus
const eventBus = createEventBus<AppEvents>()
// Fully typed events
eventBus.on('userLogin', (data) => {
// data is inferred as { userId: string; username: string }
console.log(data.userId)
})
eventBus.emit('userLogin', { userId: '123', username: 'john' })Performance Tips
Unsubscribe when done: Always unsubscribe from events when components are destroyed to prevent memory leaks.
Use
oncefor one-time events: For initialization logic that should run only once, useonce()instead ofon().Manager for cross-app communication: Use
MaxEventBusManagerfor micro-frontend scenarios instead of creating multiple independent event buses.
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
License
MIT License - see LICENSE for details.
