ivue@2.2.0 — Static() $-cached getters, order-correct per receiver
View on GitHub ↗Released July 27, 2026
ivue 2.2 teaches Static() — the stateless sibling of Reactive(), from the ivue/extras entry — a second member transform: get-only static accessors named $… become compute-once-per-receiver caches.
import { Static } from 'ivue/extras';
class $ScrollMomentum {
// a live knob — subclasses pinch it, so NO $ prefix
static get friction() {
return 2;
}
// derived once per receiver — the $ prefix is the API
static get $atRest() {
return { velocity: 0, threshold: this.friction * 10 };
}
}
export namespace ScrollMomentum {
export const $Class = $ScrollMomentum; // raw — children `extends` this
export let Class = Static($Class); // bound — you call this
}Added
$-cached static getters. The getter body runs on first read through a given class; the result is stored on that receiver and returned forever after. The cache guard checks own properties only — it never walks the prototype chain — so a parent's cache can never shadow a subclass: each class in a hierarchy derives through its own overrides on its own first read, in any read order. This is the correctness the common hand-rolled idiom (compute,definePropertyontothis, return) silently lacks.- Getters without the
$prefix stay live (they are the knobs test subclasses pinch), accessor pairs with a setter are untouched, and a subclass overriding a$-getter itself wins.
Measured
Warm-read microbenchmark (Node v26.3.1, 50M reads × 3, best-of): the caching getter costs 6.3 ns/read versus 1.1 ns for a plain data property — a single-digit-nanosecond delta, invisible at any real call frequency. Core entry unchanged at 1,112 B gzipped; ivue/extras is 494 B. Tests: 184 at 100% coverage on every metric, including order-correctness proofs in both read orders.
Note: 2.2.0 shipped cached values shallowly frozen and carried an order-dependence defect in static METHOD binding — both corrected in 2.2.1 from first-consumer field evidence.