Published PackagesEvent Bus Core
Event Bus Core
A lightweight, framework-agnostic Event Bus library for decoupled communication in modern web applications.
Event Bus Core
@web-loom/event-bus-core is a lightweight, framework-agnostic Event Bus library for decoupled communication in modern web applications. It provides a simple and efficient publish-subscribe pattern implementation written in TypeScript.
Features
- Type-safe: Full TypeScript support with type inference for event names and payloads
- Framework-agnostic: Works with React, Vue, Angular, Svelte, or vanilla JavaScript
- Lightweight: Minimal bundle size (~1KB gzipped) with zero dependencies
- Simple API: Intuitive methods for event registration, emission, and cleanup
- Flexible: Support for single and multiple event listeners
- Reliable: Stable listener execution order and memory leak prevention
Installation
npm install @web-loom/event-bus-coreQuick Start
import { createEventBus } from '@web-loom/event-bus-core';
// Create an event bus
const eventBus = createEventBus();
// Subscribe to an event
eventBus.on('user:login', (user) => {
console.log('User logged in:', user);
});
// Emit an event
eventBus.emit('user:login', { id: '123', name: 'Alice' });Type-Safe Usage
Define an EventMap interface to get full type safety and autocomplete:
import { createEventBus, type EventMap } from '@web-loom/event-bus-core';
// Define your application's events
interface AppEvents extends EventMap {
'user:login': [{ userId: string; username: string }];
'user:logout': [];
'notification:show': [{ message: string; type: 'info' | 'error' | 'success' }];
'data:updated': [{ entityId: string; changes: Record<string, any> }];
}
// Create a type-safe event bus
const eventBus = createEventBus<AppEvents>();
// TypeScript will enforce correct event names and payload types
eventBus.on('user:login', (payload) => {
// payload is typed as { userId: string; username: string }
console.log(`User ${payload.username} logged in`);
});
eventBus.emit('user:login', { userId: '123', username: 'Alice' });API Reference
createEventBus<M>()
Creates a new event bus instance.
const eventBus = createEventBus<MyEventMap>();on(event, listener)
Registers a listener function for one or more events.
// Single event
eventBus.on('user:login', (user) => {
console.log('User logged in:', user);
});
// Multiple events with the same handler
eventBus.on(['user:login', 'user:register'], (user) => {
console.log('User event:', user);
});once(event, listener)
Registers a listener that executes only once, then automatically unsubscribes.
eventBus.once('app:ready', () => {
console.log('App is ready! This will only log once.');
});
eventBus.emit('app:ready');
eventBus.emit('app:ready'); // Listener won't fire againemit(event, ...args)
Emits an event, calling all registered listeners with the provided arguments.
eventBus.emit('notification:show', {
message: 'Operation successful',
type: 'success',
});off(event?, listener?)
Unregisters listeners. Three usage patterns:
// Remove a specific listener from an event
const handler = (data) => console.log(data);
eventBus.on('user:login', handler);
eventBus.off('user:login', handler);
// Remove all listeners for an event
eventBus.off('user:login');
// Remove all listeners from all events
eventBus.off();Practical use cases
- Cross-component coordination: Share a singleton bus (e.g.,
globalEventBus) between unrelated UI fragments, such as a navigation shell and a notification toaster. Emitnotification:showfrom business logic, and let a toast queue behavior attach listeners without adding props or context. - Commands and behaviors: Packages like
@web-loom/ui-patternsinstantiate local buses to coordinate focus, flow, and layout state without referencing DOM siblings directly. - Event aggregation: Group multiple lower-level events into a single
orders:changedsignal so consumers can refresh views once per cycle instead of reacting to every CRUD event. - Filtered listeners: Create helper factories that wrap
eventBus.onbut only forward payloads that match a filter (user ID, resource type). - Global lifecycle hooks: Signal app initialization (
app:ready), environment changes (theme:changed), or cleanup (app:shutdown).
Where it's used
apps/task-flow-uiandapps/mvvm-react-integratedcreate shared providers or services that emit lifecycle, notification, and selection events without tightly coupling components.@web-loom/ui-patternsbehaviors such ashub-and-spoke,modal,toast-queue, andsidebar-shellspin up their own buses to notify siblings about state changes (selection, open/close, status updates) while staying renderer-agnostic.
Was this helpful?