Repository navigation
v0.1.45
Add a context primitive for compound components
A compound component — Select, Tooltip, DropdownMenu — owns state that every
one of its parts reads: the open flag, the active item, the shared ids.
Without a way to hand that down, each part takes it as a prop and every level
in between carries props it does not use, until the call site no longer looks
like the thing it builds.
createContext / provide / inject hang off the context stack component()
already maintains for onMount, so there is no second ownership mechanism to
keep in step. inject walks outward to the nearest provider; a context with no
default raises E_AURORA_MISSING_CONTEXT naming itself, because a part used
outside its parent is a mistake rather than a case to handle.
The one constraint is inherent to evaluating eagerly, and is documented rather
than worked around: a descendant sees the value only if the provider creates it
inside its own setup. Parent({ children: Item() }) runs Item() first and
gets nothing; Parent({ children: () => Item() }) works. A provider therefore
takes its children as a function and calls them itself.
Folded into the unpublished 0.1.46 rather than incremented.
Run onMount for a component that appears after hydration
Hydration collected mount hooks in one flat list and drained it once, at
the end of the first pass. A reactive slot that swapped its content later
kept appending to that same list, and nothing drained it again — so a
component built when the data arrived ran its setup and never its
onMount. The renderer had already met this and solved it; its
MountQueue comment describes the failure exactly. Hydration still
handed that queue flushed: false, hard-coded, so the flag it exists for
never told anyone the root was done.
flushed flips once the root has run what hydration collected. Anything
built afterwards runs its own hooks, after insertion, because a hook that
measures, positions or focuses has to see a live node.
Reactive bindings kept working throughout, which is what made it hard to
see: the symptom was a component whose whole job happens in onMount
doing nothing at all. A floating surface that only starts reacting once
it is in the document — tooltip, popover, dropdown, select — never
appeared, while the aria-describedby on its trigger toggled correctly.
A second defect came out of writing the test for the first: a subtree
hydrated inside a reactive slot put its hooks on the ROOT's queue, so
their teardowns belonged to the page rather than to the slot. Swapping
the slot removed the nodes and told the component nothing; it kept its
subscription until the whole page unmounted. That slot now carries its
own queue while hydrating too, and hands the hooks to the root's flush
through a wrapper that returns nothing — the real teardowns stay with the
slot.
Four unit tests and one in real Chromium, which is where the last one
belongs: the browser one asserts the node is laid out, not merely
attached, because a detached node measures zero and that is exactly what
a positioning hook would silently act on.
release: aurora 0.1.45
Require Node 24, and build the crates for production
Node 24, not because it is the current LTS — that is AdonisJS v7's own
stated reason and it is not one for us, since 22 still receives security
fixes until 2027, npm 11 is irrelevant under pnpm, and node:sqlite is
not what atlas uses. The reason is measurable and it is the framework's:
AsyncLocalStorage is on the request hot path, and Node 24 backs it with
AsyncContextFrame by default — 0.61 us per request instead of 1.55 us on
that exact pattern. Before 24 the same mechanism sat behind an
experimental flag, and a framework cannot base its performance on a flag
the application has to remember to pass. The reason travels with the
constraint, in a "//engines" key beside it.
Where there are crates: the default release profile leaves lto = false
and codegen-units = 16, so nothing inlines across crate boundaries —
and here the hot loop and the N-API binding that calls it are always two
different crates. Measured on atom, a scalar call through the binding
went from 18.85 ms to 13.59 ms for 50 000 operations. No panic = "abort": napi-rs catches panics and turns them into JavaScript
exceptions.
CI moves to Node 24 with them, since that is what the packages now ask
for.
Say it in English
A French word had survived in a comment on the live-client patching
rules. The repository is English throughout; this one read as a note to
self.
Changes since v0.1.44.