@sigil-dev/runtime
The macros in your components are compiled away, but the reactive core they compile to lives in @sigil-dev/runtime. You rarely import it directly — reach for it when writing a library, a test, or code that manages effects itself.
import { createSignal, createEffect, batch } from "@sigil-dev/runtime";Signals
The primitive every macro lowers to:
const count = createSignal(0);
count(); // read — 0
count.set(1); // write
count.update((n) => n + 1);
const raw = createRawSignal(0); // no deep proxycreateRawSignal is what $state.raw compiles to: writes notify, but mutating the contents of an object does not.
Reading and writing
createMemo(fn)— a derived signal that recomputes only when its dependencies change.tracking()— whether the current code is inside a tracked computation, i.e. whether a read will subscribe.untrack(fn)— runfnwithout subscribing, for a read you only want the value of.readStore(value)— read a store's value without subscribing.snapshot(value)— a deep copy as plain objects and arrays, without proxies. What$state.snapshotcompiles to.
Effects
const dispose = createEffect(() => {
console.log(count());
});
dispose();createEffect runs after the current update, re-runs when what it read changes, and returns its cleanup. Also available: createEffectPre (runs before DOM updates), createInspectEffect (a devtools hook), createProfilerEffect (timing), and flushDeferredEffects() to force pending effects to run now.
Batching
batch(() => {
a.set(1);
b.set(2);
});Without batch, two writes notify subscribers twice. With it, they notify once. Anything that sets several signals in a row — a form reset, a swap between two objects — should be batched. tick() returns a promise that resolves after pending effects have run.
Resources
const user = createResource(async (id, { refetch }) => getUser(id), () => userId());The fetcher comes first, the source signal second. user has .current, .loading and .error; the previous value stays readable while the next one loads, so a page does not flash empty on every refetch. Calling refetch() re-runs the fetcher against the same source.
Collections
ReactiveMap and ReactiveSet — reactive versions of the built-in collections, for when a signal holding an array is not the right shape. The array methods that mutate (push, splice, sort) already work on $state arrays, so these are only worth reaching for with a key-based collection.
Scheduling and scope
createRoot(fn)— runfnwith a(dispose) => voidcleanup for the whole tree. Returns whateverfnreturns.withEffectScope(fn)— collect effects created insidefnso they can be disposed together.__asyncBoundary— the marker the compiler emits around async work.
Transitions
mountTransition(element, spec, kind);
removeAnimated(element);spec is a transition function, or [fn, params]. kind is "in", "out" or "transition", and the call returns a cleanup function. easing.ts exports the standard curves — linear, easeInOutCubic, easeOutQuint and the rest. See Directives and transitions.
SafeHtml
import { SafeHtml } from "@sigil-dev/runtime";
new SafeHtml(userBio);The wrapper innerHTML requires. A plain string is a type error, which forces the decision about whether content is trusted to be explicit. SIGIL_SAFE is the symbol marking an instance.
Next
- Reactivity macros — the version you use day to day
- The reactive core — how updates are scheduled