Vue adapter bindings for Sigrea molecule modules.
npm install @sigrea/vue@sigrea/vue adapts @sigrea/core molecule modules and signals for Vue 3's Composition API. It aligns lifecycle scopes with component lifecycles, preserves deep reactivity, and provides composables for and traditional setup functions.
- Signal subscriptions. useSignal subscribes to signals and computed values, returning a readonly ref that updates when they change.
- Computed subscriptions. useComputed subscribes to computed values, mirroring Vue's computed while tracking through Sigrea scopes.
- Deep signal subscriptions. useDeepSignal subscribes to deep signal objects and exposes them as mutable refs with automatic cleanup.
- Two-way bindings. useMutableSignal wraps primitive signals as WritableComputedRef for two-way bindings like v-model.
- Molecule lifecycles. useMolecule mounts molecule factories and binds their lifecycles to Vue components.
- Install
- Quick Start
- Consume a Signal
- Bridge Framework-Agnostic Molecules
- Bind Writable Primitive Signals
- Bind Deep Reactive Objects
- API Reference
- useSignal
- useComputed
- useDeepSignal
- useMutableSignal
- useMolecule
- Testing
- Handling Scope Cleanup Errors
- Development
- License
``bash`
npm install @sigrea/vue @sigrea/core vue
Requires Vue 3.4+ and Node.js 20 or later.
`vue
{{ value }}
`
`ts
// CounterMolecule.ts
import { molecule, readonly, signal } from "@sigrea/core";
type CounterProps = {
initialCount: number;
initialStep: number;
};
export const CounterMolecule = molecule((props: CounterProps) => {
const count = signal(props.initialCount);
const step = signal(props.initialStep);
function setStep(next: number) {
step.value = next;
}
function increment() {
count.value += step.value;
}
function reset() {
count.value = props.initialCount;
}
return {
count: readonly(count),
step: readonly(step),
setStep,
increment,
reset,
};
});
`
`vue
{{ count }}
`
`vue
`
useMutableSignal expects a writable signal produced by signal(). Passing a readonly signal throws at runtime so incorrect bindings fail fast.
`vue
`
`ts`
function useSignal
signal: Signal
): DeepReadonly
Subscribes to a signal or computed value and returns a readonly Vue ref that updates when the signal changes. The subscription is cleaned up when the component unmounts.
`ts`
function useComputed
Subscribes to a computed value and returns a readonly Vue ref that updates when the computed value changes. The subscription is cleaned up when the component unmounts.
`ts`
function useDeepSignal
Subscribes to a deep signal and returns a mutable Vue ref. Updates to the deep signal trigger reactivity, and the subscription is cleaned up when the component unmounts. Templates unwrap the ref automatically, so accessing nested properties requires no .value. In script blocks, use state.value to access the underlying object.
`ts`
function useMutableSignal
Wraps a Sigrea signal as a Vue WritableComputedRef for two-way bindings like v-model. Expects a writable signal created by signal(). Passing a readonly signal throws at runtime.
`ts`
function useMolecule
molecule: MoleculeFactory
...args: MoleculeArgs
): MoleculeInstance
Mounts a molecule factory and returns its MoleculeInstance. Sigrea augments the molecule with lifecycle metadata: onMount callbacks run after the component mounts, and onUnmount callbacks run before it unmounts.
KeepAlive Support
When used inside Vue's , molecule side effects are automatically managed for optimal resource efficiency:
- On deactivation (onDeactivated): watch effects and ongoing work are paused via unmountMolecule. The molecule instance itself remains alive, preserving its internal state.onActivated
- On reactivation (): Side effects resume via mountMolecule, allowing watches and subscriptions to pick up where they left off.disposeMolecule
- On final unmount: The molecule is fully disposed via , releasing all resources.
This design prevents unnecessary computation and subscriptions while components are cached but invisible, reducing CPU and memory usage without losing state.
Props Handling
Props are treated as an initial snapshot. Updating component props does not recreate the molecule instance or update the snapshot; model dynamic values via signals or explicit molecule methods (for example, setStep).
`ts
// tests/Counter.test.ts
import { mount } from "@vue/test-utils";
import Counter from "../components/Counter.vue";
it("increments and displays the updated count", async () => {
const wrapper = mount(Counter, {
props: { initialCount: 10 },
});
await wrapper.find("button").trigger("click");
expect(wrapper.text()).toContain("11");
});
`
For global error handling configuration, see @sigrea/core - Handling Scope Cleanup Errors.
In Vue apps, configure the handler in your application entry point before mounting:
`ts
// main.ts
import { setScopeCleanupErrorHandler } from "@sigrea/core";
import { createApp } from "vue";
import App from "./App.vue";
setScopeCleanupErrorHandler((error, context) => {
console.error(Cleanup failed:, error);
// Forward to monitoring service
if (typeof Sentry !== "undefined") {
Sentry.captureException(error, {
tags: { scopeId: context.scopeId, phase: context.phase },
});
}
});
createApp(App).mount("#app");
`
This repo targets Node.js 20 or later.
If you use mise:
- mise trust -y — trust mise.toml (first run only).mise run ci
- — run CI-equivalent checks locally.mise run notes
- — preview release notes (optional).
You can also run pnpm scripts directly:
- pnpm install — install dependencies.pnpm test
- — run the Vitest suite once (no watch).pnpm typecheck
- — run TypeScript type checking.pnpm test:coverage
- — collect coverage.pnpm build
- — compile via unbuild to produce dual CJS/ESM bundles.pnpm cicheck
- — run CI checks locally.pnpm dev` — launch the playground counter demo.
-
See CONTRIBUTING.md for workflow details.
MIT — see LICENSE.