@coexist/vue

Vue adapter for Coexist.
1,048 3
Install
npm install @coexist/vue
Latest Version:2.1.0
Vue:3
License:MIT
Last Updated:Oct 24, 2026
Links: GitHub  ·  npm
Maintainer: unadlib

@coexist/vue

Vue 3 bindings for Coexist: provide/inject composables that expose a Coexist app (or a worker-hosted app) as Vue refs.

Installation

pnpm add @coexist/vue @coexist/core

Ships as ESM only: your project needs "type": "module" (or .mjs/.mts) and Node.js >=22.12.0 or a modern bundler.

@coexist/core is a peer dependency: this package shares the app runtime you install, rather than bundling a second copy of it.

Peer dependency: vue >=3.5 <4.

Quick start

Install the app with the plugin (or call provideCoexist(app) inside a parent setup), then read modules and selectors with the composables.

import { createApp as createVueApp, defineComponent, h } from "vue";
import { coexistPlugin, useComputed, useModule } from "@coexist/vue";

const CounterView = defineComponent({
  setup() {
    const counter = useModule(Counter);
    const count = useComputed(() => counter.count);

    return () => h("button", { onClick: () => counter.increase() }, count.value);
  },
});

createVueApp(CounterView).use(coexistPlugin(app)).mount("#app");

Providing the app

Function Use from Description
coexistPlugin(app) app.use(...) Provides the app for the whole Vue app.
provideCoexist(app) a parent component setup Provides the app to descendants.
workerClientPlugin(client) app.use(...) Provides a WorkerClient.
provideWorkerClient(client) a parent setup Provides a WorkerClient to descendants.

Composables

Composable Returns Description
useApp() / useCoexist() App The provided app.
useModule(token) T The bound module facade. No subscription.
useSelector(fn, opts?) Readonly<Ref<T>> Reactive ref for fn(app).
useSelector(token, fn, opts?) Readonly<Ref<T>> Reactive ref for fn(module, app).
useComputed(...) Readonly<Ref<T>> Alias of useSelector, both forms.

useModule resolves the module and nothing else — it registers no subscription, and a facade read is not tracked by Vue's reactivity. Reading state off it from a template or a Vue computed() (useModule(Counter).count) renders correctly once and then goes stale, silently. Call actions through the facade; render state through useSelector / useComputed, which re-read on every committed change — that is why the quick start above can close over counter inside the selector.

const count = useSelector(Counter, (counter) => counter.count);
const double = useComputed(Counter, (counter) => counter.double);
const version = useSelector((app) => app.state.version);

Selectors accept { equals } to control updates and clean up automatically via onScopeDispose.

Worker-hosted state

useWorkerSelector / useWorkerComputed read the client snapshot synchronously, so they throw until the host's first snapshot arrives. Await client.ready before mounting components that use them; useWorkerModule is safe at any time.

import { createApp as createVueApp, defineComponent, h } from "vue";
import { useWorkerModule, useWorkerSelector, workerClientPlugin } from "@coexist/vue";

type CounterState = { readonly counter: { readonly count: number } };

const WorkerCounterView = defineComponent({
  setup() {
    const counter = useWorkerModule<Counter>("counter");
    const count = useWorkerSelector((state) => (state as CounterState).counter.count);

    return () => h("button", { onClick: () => counter.increase() }, count.value);
  },
});

createVueApp(WorkerCounterView).use(workerClientPlugin(client)).mount("#app");
  • useWorkerClient() → the provided WorkerClient.
  • useWorkerModule<T>(name) → an AsyncMethodProxy<T>.
  • useWorkerSelector(fn, opts?) / useWorkerComputed(fn, opts?) → Readonly<Ref<T>> of worker state.

Exports

coexistPlugin, workerClientPlugin, provideCoexist, provideWorkerClient, the CoexistKey / WorkerClientKey injection keys, useApp, useCoexist, useModule, useSelector, useComputed, useWorkerClient, useWorkerModule, useWorkerSelector, useWorkerComputed, and the UseSelectorOptions / AppSelector / ModuleSelector types. The use* composables throw a CoexistError when the app or client was never provided.

License

MIT © Coaction

Version History

Version Released Vue License
2.1.0 >=3.5.0 <4 MIT
2.0.0 >=3.5.0 <4 MIT
1.1.0 >=3.5.0 <4 MIT
1.0.1 >=3.5.0 <4 MIT
0.2.1 >=3.5.0 <4 MIT