Vue
Postboy is framework-agnostic — the messages, registrators, and the bus API are exactly the same as in any other environment. Vue simply answers two questions differently than Angular or React: how the bus instance is shared (no hierarchical class-based DI) and how subscriptions are tied to the component lifecycle (scopes instead of ngOnDestroy /effect cleanup).
The guide below uses Vue 3 with the composition API; a Vue 2 note is at the end. For the framework-agnostic model, see Concepts, Message roles, Events, Callbacks, and Executors.
Installation
rxjs ^7 is the sole peer dependency — install it too if your project doesn't have it yet. Postboy major lines follow the RxJS generation of your project (1.x for ^6, 3.x for ^7); see Versions for details.
The bus instance
Two idiomatic options; the second one is recommended because it keeps components testable.
Option A: module singleton
The quickest start:
Construct the service with no arguments — the optional constructor parameter exists for internal dependency injection, not for configuration.
Option B: provide/inject (recommended)
Components then receive the bus via inject(POSTBOY) — and tests can mount the same component with the recording mock from @artstesh/postboy-testing instead (see below), without module mocking.
Messages
Message classes are plain TypeScript, shared with any other part of the system:
Every class declares its own unique static readonly ID — that string is the routing key. See Message roles.
Application-level registrations
A registrator wires the global messages once, at startup:
up() runs in main.ts before app.mount(...) — registrations must exist before components subscribe. The same ordering rule as in every other framework applies: define → register → subscribe → fire. See Registration and Lifecycle management.
Subscribing in components
The Vue-idiomatic way is a small composable that ties an RxJS subscription to the current scope — it is disposed automatically when the component unmounts:
onScopeDispose works inside setup() and inside composables called from it — no manual onUnmounted bookkeeping per subscription. Assigning to ids.value updates Vue's reactivity automatically, so no change-detection calls are needed (unlike Angular's OnPush).
Component-owned registrations
When a component (a modal, a complex filter block) owns a handful of messages, skip the registrator class and use a namespace tied to the component's lifetime:
Eliminating the namespace disconnects everything recorded in it — the streams complete, and the subscriptions above end with them. See Namespaces for the full semantics and the infrastructure messages reference for the exact signatures.
Requests and commands
Callback messages and executors work the same as anywhere; in Vue they pair naturally with async handlers:
fireCallback with an action dispatches immediately; without one it is lazy — it sends on the first subscription. finish(...) completes the result stream, so firstValueFrom resolves exactly once per query instance. exec is synchronous — never await it. See Callbacks and Executors for the full models.
Testing
With the provide/inject setup, @vue/test-utils mounts the component over the recording mock of @artstesh/postboy-testing:
If you chose the plain module singleton (option A), tests need vi.mock/jest.mock of the bus.ts module instead — the provide/inject variant avoids that entirely. See Testing for the toolkit itself.
Vue 2 (options API)
The library works the same; only the wiring differs:
share the bus via the module singleton (option A) — Vue 2 has no typed
provide/inject;subscribe in
created()/mounted()and unsubscribe inbeforeDestroy():
Where to go next
Cookbook — the same patterns framework-agnostic
Angular and React — the same integration story in other ecosystems
Ecosystem integration — what differs per framework at a glance
Testing — the Given/When/Then toolkit in depth