ivue@2.3.0
View on GitHub ↗Released August 23, 2026
Feature release — one new export, zero breaking changes, and the core engine untouched: ivue/extras gains LazyShared, the cell that closes the last open seam in the class-module system. The primary ivue entry stays the bare 1.1 kB engine.
LazyShared — the safe shared-store cell
A shared static store has to hold two properties at once, and until now JavaScript made you pick one:
- Load-lazy — a
static readonlyfield initializer runs at module load, so constructing another module's class there races the import cycle.$-cached static getters defer correctly — but they cache per receiver, so a subclass reads a fresh, empty copy. - Unforkable — one value per process, every access path — base class, subclass,
$-cache — converging on the same object.
LazyShared is both. The field eagerly stores the cell; the cell holds an inert thunk; the value constructs on first read — after every import cycle has resolved — and memoizes inside the cell, never on a receiver, so there is nothing forkable at the end of any access path:
import { LazyShared } from 'ivue/extras';
class $SearchRegistry {
protected static readonly sharedBackend = new LazyShared(
() => new SearchBackend.Class(),
);
protected static get $backend() {
return this.sharedBackend.value;
}
}The surface is three members — new LazyShared(make), .value, .reset() (the test seam) — and two failure modes are engineered rather than left to chance: a thunk cycle throws a named error that tells you which dependency to break, and a throwing thunk never poisons the cell (the next read retries).
With it, the combined Reactive() + Static() system is memoizable at every scope — instance, receiver, shared — with polymorphism, inheritance, and performance intact. The full map, every value kind in working code: Bulletproof class modules.
The Standard, grown again
npx ivue skill ships the current Standard Operating Manual (845 → 1,033 lines), with the conventions that landed alongside the new cell:
self— the one cast per class. Instance code reads its own statics throughprotected get self() { return this.constructor as typeof $X }— late-bound, so subclass overrides are honored, and declared once beside the statics it types instead of asserted at every call site. Measured: ~2 ns per read over an inline cast; the hoistedconst self = this.selfform in loops measures faster than inline casts (~0.4 ns vs ~4 ns per iteration, Node 26, production build).- The shared-store split as two questions. Does a subclass get its own copy (memo →
$-getter) or not (registry →static readonlyfield pin)? And does construction cross a module boundary (→ the field holds aLazySharedcell)? - Restructured for coherence: the manual now reads as three parts — the
Reactive()instance world, the static world fromivue/extras, and the style contract.
Docs
- New guide page: Caches, Registries &
self— the fork trap, the static-field pin, the load-order boundary,LazyShared, and theselfidiom, with the decision table. - New posts: Bulletproof class modules and The Options API everyone actually wanted.
Numbers
- Core
ivueentry: byte-identical to 2.2.2 — 1.1 kB gzipped, zero dependencies. ivue/extrasgrows by the ~40-line cell; engine and extras test coverage stays 100%.