RouteBus: Type-Safe Event Bus
I keep writing the same pub/sub code in every project.
A thing happens. Other things need to know. So I create an event emitter. Then I realize I want type safety. Then I need it to work across browser tabs. Then across services. Then I am maintaining three different implementations that do almost the same thing.
So I built RouteBus to stop doing that.
The idea
One event bus interface. Pluggable transports underneath. Start simple, scale up without rewriting code.
|
|
TypeScript autocompletes the event names. Try to emit with the wrong payload type and you get a compile error, not a runtime bug.
Why transports matter
The default transport is in-memory. Events stay in the current process. Fine for most things.
But then you need cross-tab sync. Or you are building a multi-server app. Same events, different plumbing.
BroadcastChannel for browser tabs:
|
|
Redis for distributed systems:
|
|
Same bus.on, same bus.emit. The transport handles where the events actually go.
Type safety that catches things
This is the part I cared about most.
|
|
Event names autocomplete in the editor. Invalid payloads fail at compile time. No more "why is this undefined" debugging sessions.
Event queuing
Sometimes you do not want to emit immediately. Batch processing, debouncing, whatever.
|
|
enqueue buffers the events. drain processes them with whatever logic you want. Simple, but it covers most of the cases where I would otherwise reach for a queue library.
Custom transports
If the built-in transports do not fit, you can write your own:
|
|
Three methods. That is the whole interface. I have used this to wire up WebSocket connections and custom message queues without touching the rest of the app.
What I actually use it for
UI state sync across tabs. User logs in on one tab, all tabs update. No localStorage polling.
Decoupling modules. Instead of direct imports, modules just emit and listen. Easier to test, easier to swap things out.
Microservice communication. Same event definitions shared across services. Redis transport underneath. Type safety end to end.
The tradeoffs
It is zero dependencies and tree-shakeable, but it is not trying to be a full message queue. No persistence, no guaranteed delivery, no dead letter queues. If you need that, use an actual message broker.
But for the 90% of cases where you just need "thing happened, other things should know", this is the tool I reach for now.
Links
RouteBus: https://github.com/Cr0wn-Gh0ul/RouteBus
npm: https://www.npmjs.com/package/routebus