@coexist/solid
v1.1.0
Published
Solid adapter for Coexist.
Downloads
220
Readme
@coexist/solid
Solid bindings for Coexist: a context provider and signals for consuming a Coexist app (or a worker-hosted app).
Installation
pnpm add @coexist/solid @coexist/coreShips 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: solid-js >=1.9 <2.
Quick start
import { CoexistProvider, useComputed, useModule } from "@coexist/solid";
function CounterView() {
const counter = useModule(Counter);
const count = useComputed(Counter, (module) => module.count);
return <button onClick={() => counter.increase()}>{count()}</button>;
}
<CoexistProvider app={app}>
<CounterView />
</CoexistProvider>;useComputed returns a Solid Accessor<T> — call it (count()) to read inside JSX or an effect.
API
| Function | Returns | Description |
| ------------------------------- | ------------------ | ----------------------------------------- |
| useApp() | App | The app from CoexistProvider. |
| useModule(token) | T | The bound module facade. No subscription. |
| useComputed(fn, opts?) | Accessor<T> | Signal for fn(app). |
| useComputed(token, fn, opts?) | Accessor<TValue> | Signal for fn(module, app). |
| useSelector(...) | Accessor<T> | Alias of useComputed, both forms. |
useModule resolves the module and nothing else — it creates no signal, and a facade read inside a tracking scope is not tracked by Solid. Reading state off it (useModule(Counter).count) renders correctly once and then goes stale, silently. Call actions through the facade; render state through useComputed.
Both useComputed overloads accept { equals } (defaults to Object.is) and clean up with onCleanup.
const count = useComputed(Counter, (m) => m.count);
const version = useComputed((app) => app.state.version);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 { WorkerClientProvider, useWorkerModule, useWorkerSelector } from "@coexist/solid";
type CounterState = { readonly counter: { readonly count: number } };
function WorkerCounterView() {
const counter = useWorkerModule<Counter>("counter");
const count = useWorkerSelector((state) => (state as CounterState).counter.count);
return <button onClick={() => counter.increase()}>{count()}</button>;
}
<WorkerClientProvider client={client}>
<WorkerCounterView />
</WorkerClientProvider>;useWorkerClient()→ theWorkerClientfrom context.useWorkerModule<T>(name)→ anAsyncMethodProxy<T>.useWorkerSelector(fn, opts?)/useWorkerComputed(fn, opts?)→Accessor<T>.
Exports
CoexistProvider, WorkerClientProvider, the CoexistContext / WorkerClientContext contexts, useApp, useModule, useComputed, useSelector, useWorkerClient, useWorkerModule, useWorkerComputed, useWorkerSelector, and the CoexistProviderProps, WorkerClientProviderProps, UseComputedOptions, AppSelector, ModuleSelector types. Hooks throw a CoexistError when the matching provider is missing.
License
MIT © Coaction
