Repository navigation
Release RC packages (rc) - #4683
Open
github-actions[bot] wants to merge 1 commit into
Open
github-actions[bot] wants to merge 1 commit into
github-actions[bot] wants to merge 1 commit into
Conversation
github-actions
Bot
force-pushed
the
changeset-release/next
branch
30 times, most recently
from
November 10, 2026 16:24
1398c4d to
cd0c63e
Compare
github-actions
Bot
force-pushed
the
changeset-release/next
branch
29 times, most recently
from
November 12, 2026 21:37
704c5e0 to
dd078d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to next, this PR will be updated.
nextis currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, runchangeset pre exitonnext.Releases
@solidjs/babel-plugin@2.0.0-rc.22
Patch Changes
istanbul/c8ignore pragmas through the remaining Cannot use istanbul ignore comments for generated code #2138 cases: a pragma immediately before a component (including through a fragment) leads that component'schildrengetter, pragmas inside fragments are preserved, and SSR prop-hoist copies them onto the shared descriptor'sget().User :in<h1>User : {name()}</h1>, used to getvar _el$3 = _el$2.firstChildeven though the insert appends with anullmarker. A minifier keeps that property read, since it could be a getter, so it shipped as_el$2.firstChild;. Both compilers now drop afirstChild/nextSiblingwalk when no later statement reads its node, including a walk that only fed another dropped walk.<Show>that needs no component to the ternary it renders: nokeyed, no spread, onlywhenandfallback, with JSX children or a one-parameter callback whosewhenis a plain read (eachu()readswhenagain). Dev builds keep the component and its stale-read error. ThelowerShowoption overrides the default (!dev). The native compiler's SSR pass also no longer returns a TSRX module's static templates unescaped when one element in the module is marked as safe.&&, and in everyreturnof a function child, including areturninsideif,switch,tryor a loop. The server now renders them as text, as the client does, in children and in attribute values (Server build does not escape a string literal in a ternary branch or after && #4710). A function value in an attribute keeps its literals as written at every depth, because the server stringifies its source.<style>and<script>under<svg>and<math>. There they are ordinary elements whose text parses as markup, so only HTML-namespace<style>/<script>render raw text (<style>and<script>children inside MathML are not escaped in SSR (and static DOM templates), allowing markup injection #4704).@solidjs/compiler@2.0.0-rc.22
Patch Changes
istanbul/c8ignore pragmas through the remaining Cannot use istanbul ignore comments for generated code #2138 cases: a pragma immediately before a component (including through a fragment) leads that component'schildrengetter, pragmas inside fragments are preserved, and SSR prop-hoist copies them onto the shared descriptor'sget().User :in<h1>User : {name()}</h1>, used to getvar _el$3 = _el$2.firstChildeven though the insert appends with anullmarker. A minifier keeps that property read, since it could be a getter, so it shipped as_el$2.firstChild;. Both compilers now drop afirstChild/nextSiblingwalk when no later statement reads its node, including a walk that only fed another dropped walk.<Show>that needs no component to the ternary it renders: nokeyed, no spread, onlywhenandfallback, with JSX children or a one-parameter callback whosewhenis a plain read (eachu()readswhenagain). Dev builds keep the component and its stale-read error. ThelowerShowoption overrides the default (!dev). The native compiler's SSR pass also no longer returns a TSRX module's static templates unescaped when one element in the module is marked as safe.&&, and in everyreturnof a function child, including areturninsideif,switch,tryor a loop. The server now renders them as text, as the client does, in children and in attribute values (Server build does not escape a string literal in a ternary branch or after && #4710). A function value in an attribute keeps its literals as written at every depth, because the server stringifies its source.<style>and<script>under<svg>and<math>. There they are ordinary elements whose text parses as markup, so only HTML-namespace<style>/<script>render raw text (<style>and<script>children inside MathML are not escaped in SSR (and static DOM templates), allowing markup injection #4704).@solidjs/diagnostics@2.0.0-rc.22
Patch Changes
@solidjs/element@2.0.0-rc.22
Patch Changes
@solidjs/h@2.0.0-rc.22
Patch Changes
@solidjs/html@2.0.0-rc.22
Patch Changes
setTrustedTypesPolicy(policy), so Solid renders on pages that enforcerequire-trusted-types-for 'script'. The app passes a Trusted Types policy it created, and the runtime assigns theTrustedHTMLthat policy returns, for compiled template markup, for the server HTML the frames client parses, and for thehtmltagged template's text decoding. On the server it is a no-op, so an isomorphic entry can call it. Nothing changes for apps that do not call it.@solidjs/signals@2.0.0-rc.22
Patch Changes
5755ddd: A pass that asks and reads ahead runs on the screen as a sync pass does (S-51 re-ruled 2026-11-12; F-2, F-6, D-25, [2.0 / next] Wrapping isPending() in a memo changes the result of an otherwise identical async derivation #4778). An async memo that reads a held value beside
latest(),isPending()or a guess of it now answers the screen's question for the display —0/true,0/1beside the screen'sid— and the landed world's question for the frame, so the write never shows beside another question's answer. The 2026-11-07 producer clause ("a question is asked only of the truth") is withdrawn: under itisPending(id)readtruebeside an async label computed fromfalse, and a wrapped async reader (memo(() => asyncMemo())) behaved differently from an inline one.The hold waits for the answer to its own question. The request the frame's pass sent is the hold's question; the hold waits on it while a reader on screen does, whatever the screen's pass came to (before, a faster screen answer could land the write ahead of its data). A second write while that request is up supersedes it: the reader asks the new question at once instead of at the landing, and never ends on the first write's answer (on
next,async(source(), memo(latest(source)))did). A window extracted into a memo reads as inline for an async reader over it, in either read order.A derived store whose derive reads such a memo shows what the memo form shows (D-30).
cf32a50: A projection whose function returns another store as is now reads that store's values after a switch made while a guess is out (2.0: a keyed projection whose fn returns another projection loses a row after a switch with a guess out #4762). The outer store's own nodes still carried values from an earlier pass in the guess's lane. Once the store was chained, those values covered the inner store, so
lengthand a row of the old list were served beside the new list's rows. A chained store's nodes now read through to the inner store. Guesses on an optimistic store are still served first.ce7b4bb: fix(signals): a guess standing in for another action's held refresh keeps that hold waiting for the refetch ([2.0 / next] createOptimistic: two pending guesses are dropped when one action's write lands, while another action's store guess and both refreshes are still out #4786)
aaf528d: Three lane-engine arms that no suite, pin or generator case has ever executed are removed:
heldBy(the "frame parked by one pass alone" exemption at the seam, [2.0 rc.20] useIsRouting() stays false through a held navigation when an effect tracks it and a <Show when={latest(x)}> exists (regression from #4356) #4439 — it never returned true, not even in the suite of the commit that introduced it), thebornHeldOpentail ofattachWaits([2.0 / next] A display-ahead <Show> opened under a plain write's hold attaches its branch with an empty text hole until the landing (S-46, F-2) #4574 — the mount stamp of S-46/S-58 seats a born-held mount before anything inserts it, and lane work never joins a hold, D-37, so the walk never found a node), andunder(nested lanes cannot exist: a lane is never the flush's transaction, D-37, so no guess is ever parented to one). The lane link merge (linkLanes, A15 for lanes) stays: it is reachable — four in-flight optimistic actions read as two pairs, then a later reader across the pairs — and now has a pin. No behavior change; −260 B brotli / −900 B minified on theisPending/latestchunk.d476295: Remove the "transaction only a
latest()read opened" arm (latestOpened/openedByLatestand thestagedScreentest on it).latest()has opened no transaction since fix(signals): latest() opens no transaction for its verdict; its reader watches the seam (#4365) #4393, so the flag was never set and the arm could never run; a coverage inventory across every suite and 150,000 generator cases confirmed it (reader-seat-rebuild.md §9.5). No behavior change; −63 B minified on theisPending/latestchunk.f6b6737: Add
DEV.setSignalso development tooling can write signal values and store property slots (Add DEV.setSignal so devtools can write a signal or store node #4679).2789ca9: A display-ahead gate is the same mainline mount with any number of memos between the probe and the branch (S-58, D-25). A hand-written gate — one memo that probes and mounts, or a truthiness memo with a branch memo reading it — now keeps its fallback through the flight and attaches at the landing, as
<Show>and the compiled ternary do: a probe's held reader whose frame holds a born-held mount is no longer published with its hole empty when the probe re-derives to the same value at the seam, and a mount under an open action counts as still waiting. The plain read under an errored boundary inside an action (S-53′) attaches at the landing with it.db3d13d: A mount a display-ahead gate opens keeps its seat whatever its own first pass reads ahead (S-58′, D-25). A branch leaf that reads
latest(x)beside a plainx()in one grouped effect, under a hand-written gate, attached early with the committed value beside its own ahead read; it is now born held like a plain-only leaf, as it already was under<Show>and with one effect per attribute. Neither hop count nor grouping changes the screen. The same mount under a guess lane (the write inside an action on an optimistic signal) was served the committed value of the lane's re-asked node by the lane's stale-reader arm and revealed with it at the action's landing, through<Show>as through a hand-written gate; it is now born held on the lane's flight too (S-58″, S-58‴).bc423eb: fix(signals): a display-ahead
<Show>(or ternary) keeps its fallback while the write that opened it is held, whatever the child's shape: element, fragment, text beside a hole, function child, or plain text (S-46, S-58, [2.0 / next] A display-ahead <Show> is born held only with an element child: text, fragment and function children attach early (fragment form regressed in #4720) #4806)5208944: Prevent an untracked staged-store read beside
latest()from throwing and halting reactivity when the store has no reactive node. A pass whose verdict posture is only inherited is now served the hold's own write from a node-less store key, as it is from a signal or a key with a node, so the landing frame no longer tears.6751472: fix(verdict): a reader of a guess in the guess's own lane is not marked with the truth's staged error, so a failure under an open hold no longer shows early beside readers that keep the guess ([2.0 / next] createOptimistic: a guess after a failed refresh replaces the shown error, and a production build never shows the error #4751)
5ecd72f: A guess an action writes after reading another action's live guess, in its body or its setter, now entangles the two actions: neither guess reverts while the other action is out ([2.0 / next] Optimistic setter can consume another action’s guess without entangling its lifetime #4788).
4de85c2: fix(store): a guess computed from another action's live guess through a replaced child, an
incheck or key enumeration derives from it, as a direct read does ([2.0 / next] Optimistic read dependencies missed through replaced children, presence and key enumeration #4812)6b7474b: An async memo that reads
isPending(x)no longer shows its verdict beside anisPending(x)binding that disagrees with it, and nothing derived from the write it reads ahead of shows before that write does ([2.0.0-rc.20] isPending disagrees with an async memo derived from it #4677).pending: trueshowed while the binding stayedfalse. The lane now reveals whole (F-6), and the landing's re-derivation follows next round.details: Item 1showed besideid: 0. Those runs now wait with the landing's held runs (F-1, F-7); what derives from a verdict reader still shows now (F-6, D-25).dc33de6: At a hold's landing, a memo that read the screen while the hold was up (for example
[latest(x), x()]orisPendingbeside a held write) no longer shows its stale value for one frame. The runs of its readers that were held with the landing now re-run on its re-derived value.f00ce6f: Rows that a held optimistic lane built keep their text when a correction ends the lane: a render effect born in that frame now runs on the committed values instead of losing its first run with the lane's parked runs (For over a keyed projection renders rows with no text after guesses and a list switch #4831).
da402ca: fix(lanes): a corrected guess lane voids a staged error with the rest of its staging, so a refresh's failure reaches
Errored([2.0 / next] createOptimistic over a derived signal: when the guessing action's own refresh fails, the error never reaches Errored #4748)79b6541: The lane engine is split along the guess boundary:
lanes.tskeeps the sub-hold core every lane needs (the lane record, link / blocked / reveal / landing, the lane read and a lane pass's tail — whatisPending()andlatest()install for their verdict lanes), and the newguesses.tscarries what only a written guess reaches (createOptimistic/createOptimisticStore:optimisticWrite, the seam'sapplyGuesses,take,supersede,laneCorrections,laneOutcome, a write landing on a guess, a revert landing's give-back), installed behind hooks when imported. Pay-for-use (Bundle size audit: pay-for-use tree-shaking for @solidjs/signals subsystems #2883): an app usingisPending/latestwithout optimism no longer ships the guess layer (−531 B brotli on+ isPending/latest, −454 to −533 B on the live pages); an app with both pays the indirection (+15 B brotli). No rule or screen changes.45498e3: An error seen through
latest()now publishes with its reader, as a value would. Inside an open action, an<Errored>aroundlatest(m), or around a memo of it, showsm's held error ahead, and later errors and the recovery reach that fallback the same way. Plain readers still wait for the reveal (D-41).e0f31bc:
mapArray(and<For>) copies its source list once at the start of a pass and diffs that copy, instead of reading the list throughout the pass and copying it at the end. A deep store list answers every slot read through a proxy trap, so each slot went through the proxy three or four times per pass and now goes through once. Removing 100 scattered rows from a 1,000-row store list goes from about 0.82 ms to about 0.72 ms, and bundles withmapArrayare 23 bytes smaller minified. A plain array does the same single copy as before, earlier in the pass.1bdd973:
mapArrayandrepeatrun their update pass in a module-level function instead of an arrow function created on every pass. V8 keeps optimized code for a closure only while an instance of it is alive, so each major GC discarded the list update's optimized code and the next passes ran in the baseline tier. Appending one row to a 500-row list right after a major GC goes from about 26 µs to about 4 µs. No behavior change.0895916: A memo over
latest()orisPending()that only the screen reads now shows what the same reads inline show ([2.0 / next] A memo over latest() publishes ahead of an ordinary memo consuming its output #4776). Once a hold's own work reads it, such as a branch the hold opened or an async derivation, it becomes that hold's work, so the async asks only of the truth ([2.0 / next] Wrapping isPending() in a memo changes the result of an otherwise identical async derivation #4778).edeb5db: fix(store): a store setter writing a nested key inside another store that is still loading its first answer no longer throws
NotReadyError. The nested write is dropped, as a write to a loading store is replaced by its first answer, and the outer store keeps following the inner one. Dev warns withSTORE_WRITE_THROUGH_LOADING([2.0 / next] An ordinary store setter throws NotReadyError on a blind nested write through a pending store #4808).a01fd92:
onFlushcallbacks now each run in their own flush. Before, several callbacks queued in one frame batched into a single flush, so async work one of them started held the others' writes with it. Each callback is now its own frame (D-4): it commits on its own unless what it changes derives from held work.d00f055: An optimistic array guess no longer keeps serving another action's expired guess at indices it did not itself write ([2.0 / next] Optimistic array retains an expired guess when another action writes a different index #4784). A guess's frame is composed on the view, so it holds the other guess's values at keys outside its own record; an arrangement read now falls through on those carried-over keys — to the lending carrier while it lives, to the truth once it dissolves — instead of serving the frame's stale copy. Writes that change no keys and no length already belonged to the changed indices ([2.0 / next] createOptimisticStore: whole-array guesses hide a guess made during another action's refresh, and a failed refresh never shows its error #4724); the read side now matches when the lending guess expires while a disjoint guess is still out.
38b6f85: fix(signals): two optimistic guesses that change an array's keys or length hold the list together again: the [2.0 / next] Optimistic array retains an expired guess when another action writes a different index #4784 fall-through to a lending guess applies only to index writes that change neither (D-33)
4fe7532: An optimistic guess corrected by an outside re-ask now stays the value for effects and untracked reads until its action's own refresh lands ([2.0 / next] A guess reverts at the action's end, before the refresh the action issued lands, once an outside re-ask has landed under it #4690). When a
refresh()from outside the action landed under a pending guess (createOptimistic, or acreateOptimisticStorekeyed, unkeyed or object-shaped), the action's hold stopped waiting on the guessed source's next flight. Where nothing rendered the source, the hold landed with the action's write, and effects and untracked reads showed the old truth until the action'srefresh()answered, while rendered readers (a render effect, a text node under<Loading>, an effect beside one) kept the guess. Rendered output never flickered; effect-only readers disagreed with it. A shown guess that was corrected now keeps its hold open while its own source is in flight, as an uncorrected guess does.ccb438d: fix(signals): a write is not held by an action whose hold waits only on its
refresh()([2.0 / next] After switching away and back during a write's refresh, a memo picking between two optimistic stores shows the other store at rest #4828)A memo that an action's hold had pending only on that action's
refresh()pulled a later, unrelated write into the hold (switching a filter between two optimistic stores). The action's guess keeps its hold open until the refresh answers, so the switch, the other list's answer and the switch back all waited for it, and the refresh's landing then showed the other store's rows. A re-ask holds nothing new: the memo now leaves the hold and its next pass is the write's own frame.78eaf88:
createOptimisticStore: a setter that returns a new array is written as the keyed diff of what it changed, so it reads the same at every frame as the equivalent field write ([2.0 / next] createOptimisticStore: a returned whole-array guess hides its own refresh's failure from Errored #4737, [2.0 / next] After #4729: a guess made during a returned guess's refresh still waits for that refresh #4739). While guesses are out, a landing keeps every keyed row's proxy, so a row whose earlier guess settled can be guessed again and shows ([2.0 / next] createOptimisticStore: a field guess never shows after another action's landing re-derives the store while guesses are out #4738).cd4de28: Two guesses on one optimistic store around another action's
refresh(): a render effect waiting on that refresh (through a projection) now shows a new guess with the other readers of its slot ([2.0 / next] An effect sees a store guess that the render of the same slot holds back (guess made during another action's refresh) #4824), and a second guess on a slot no longer disappears when the first guess's action ends while the second is still out ([2.0 / next] A second guess on one store slot is dropped when the first guess's action ends, while the second is still out #4825).e76279f: Dev now warns
OPTIMISTIC_WRITE_WHILE_LOADINGwhen an optimistic setter runs while its source, which has answered before, is loading a new question. The setter composes on the previous answer, and the new answer replaces the guess ([2.0 / next] A guess written while its source loads a new question runs over the previous question's answer #4795).8b7254a: fix: a memo's two plain reads of a held value agree when its first
latest()/isPending()of it comes between them ([2.0 / next] Two ordinary reads of the same signal return 1 then 0 when latest() is called between them #4777)46a72c0: A question is asked only of the truth (F-2's producer clause, F-6's limit), on the M1 lane value model. An async derivation that reads a held value plainly beside
latest()/isPending()is the hold's work: it asks once, of the truth, never of the value the screen keeps (S-51, [2.0.0-rc.20] isPending disagrees with an async memo derived from it #4677).isPendingstays true for a landed answer the lane still holds on a sibling's flight (S-54, 2.0.0-rc.21: isPending clears before a changed optimistic result is revealed #4685). A held recovery to the last good value is a change of answer andlatestshows it ahead, so an errored boundary recovers while the action is open (S-53, [2.0 / next] An action that un-poisons a throwing memo under an Errored showing its fallback (Show when=latest(m)) wedges the flush: Potential Infinite Loop Detected (last staged node: value) — async generator seed 3289 case 3963 #4403). A guess written to an optimistic memo before its first answer shows and the first answer judges it (S-56; the memo-formOPTIMISTIC_WRITE_BEFORE_LOADguard is gone, the store form keeps it).[isPending(x), x()]shows pending beside the kept value in every shape, a sync-ending action included (S-52, [2.0 rc.17 – next] refresh(memo) inside an action loops forever when a render effect reads isPending(memo) #4349). A plain write whose derivation became a guess's lane work holds on that flight and reveals with the lane (S-57). The branch a display-ahead<Show>opens is born held: the fallback stays through the flight and the branch attaches at the landing, for<Show>and the compiled ternary alike (S-46's plain row).latest()of a displayed optimistic guess keeps the guess over a correction until the commit, for a signal and a superseded keyed row ([2.0 / next] latest() over an optimistic guess answers the re-asked truth once a re-ask lands while the guess is pending #4689).Lane values now live on the node's two slots with the cover recorded explicitly (M1): the separate lane slot,
display()andlaneValueOfare gone.abbb806: fix(store): presence and keys of a slot a lane pass derived read the same frame as its value, so
mapArrayover a keyed projection no longer maps an empty slot after a declined removal ([2.0 / next] mapArray over a keyed projection maps an empty slot after a declined removal guess (regression from #4785) #4821)6681c1b: A projection read by another projection's derive is brought up to date before it is read, and its reader is ordered after it. A write that dirtied N rows no longer re-ran each downstream reader up to N times ([2.0 rc.21]: a projection that reads a memo is read stale by another projection's derive, so a derive over N such readers re-runs N times (O(N²) per flush) #4782).
a8b8b67: fix(signals): a guessed store re-asked through its sources is a re-ask, not a new question held behind the guess's action ([2.0 / next] Re-asking a guessed store holds until the guess's action ends, but only when a write to another source is still pending #4801)
9c917ea: A ref callback that reads a sync memo on a row mounted while an async memo is in flight no longer leaves that update held forever ([2.0 rc.14+] A ref that reads a memo on a row mounted during an async memo's flight leaves the update held forever (production builds only) #4767). Refs run in the attribute effect's commit half with no owner; a memo born into the hold has only a staged value, and an ownerless read of it threw
NotReadyError(A19 exception 1), which errored the effect mid-hold so the transaction never landed.runRefCallbacknow marks the read, andservereturns the staged value only when the ref's creating pass was born into that memo's hold (F-7); productionref()always goes throughrunRefCallbackso the mark is present outside dev too.7230c08: A ref callback (
ref={el => …}) now runs the way a render effect's callback runs at creation ([2.0 rc.21 / next] A non-keyed <Show>/<Match> branch hidden by an optimistic write throws a stale read from its ref on restore and halts reactivity #4761). It is untracked and runs in the context of the pass that creates the element, so its reads see what that pass is building. Before, it ran with no owner, so its reads were outside reads that saw the screen before the pass committed. A non-keyed<Show>/<Match>branch that an optimistic write had hidden could not come back: its ref read the narrowed accessor, got the old falsy condition, and threw a stale read that halted the app.A ref still owns nothing. In dev, creating a memo, effect or root inside it throws
PRIMITIVE_IN_EFFECT_CALLBACK, andonCleanupinside it throwsCLEANUP_IN_FORBIDDEN_SCOPE. Set those up in the factory that returns the ref, which runs in the component body. Writes,refresh, action calls andonFlushstay allowed in a ref, as in an effect callback.9d4f077: A second optimistic guess whose consequence is still pending no longer reaches a reader re-run by an unrelated write: it is shown with its lane's next reveal ([2.0 / next] A second optimistic guess leaks to an ordinary reader while its async consequence is held #4775).
fb672ca:
IMMUTABLE_UPDATE_IN_STOREno longer reports wholesale replacements on a shallow store, or of amarkRaw/ unwrappable leaf (v2-rc.21: Shallow store produces diagnostic when replacing a value #4686). Those values are invalidated as a unit, so leaf draft assignment does not narrow who re-runs — the diagnostic's advice does not apply.e76279f: A guess shown while its source loads a new question stays on screen until its action's hold commits, instead of giving way to the new question's answer while the action is still out ([2.0 / next] A guess written while its source loads a new question runs over the previous question's answer #4795).
b050983:
mapArray's small-move pass (a swap, a rotate or a few displaced rows in a plain<For>) records each aligned run once and checks displaced rows for duplicates with a native scan of the window, instead of building aSetand probing every aligned row. A swap on 1,000 rows goes from about 10 µs to about 4.5 µs, and bundles withmapArrayare 97 bytes smaller minified. No behavior change.9de15ba: fix(signals): a staged store error read from a bare owner (a
<For>row update) no longer links it as a computation, so<Errored>gets only the fetch's error ([2.0 / next] createOptimisticStore: a refresh that rejects under an optimistic add hands <Errored> an internal TypeError and undefined before the fetch's error #4805)d06e7a7: A bundle that uses stores without importing
deep()no longer ships the store's deep-tracking bookkeeping: the write and reconcile paths check a module flag that onlydeep()sets, so a bundler drops the guarded code.c981680: An optimistic store's guess is one node per setter per lane: the guess carrier, whose value is the setter's draft with the keys it changed recorded on it. Reads of a guessed key go through the carrier; a landing is judged against it over those keys. A rewritten or returned top-level array is one write per index that differs, as a returned object is one per key, and the list itself is the slot only when its keys or length changed. Two actions guessing into one list (a field edit and a whole-array rewrite alike) are two carriers in two lanes: a guess made while another action's refresh is in flight shows from its flush, and the refresh's failure is the list's answer and reaches
Errored([2.0 / next] createOptimisticStore: whole-array guesses hide a guess made during another action's refresh, and a failed refresh never shows its error #4724). TheOPTIMISTIC_REVERTEDfinding names the guessed key.b3e9fb8: A spread or a
merge()/omit()consumer that reads the keys of a store now asks the store's handler for them directly instead of going through the proxy withReflect.ownKeys. The engine validates every proxyownKeysresult against the proxy's target, and for a store that check cost about twice the trap itself. Reading the keys of a 12-key store this way goes from about 880 ns to about 280 ns, and re-running an element spread over a store record takes about 10% fewer instructions. The keys returned and the tracking are the same; any other proxy (a merge or omit view, a projection draft, a foreign proxy) is still read throughReflect.ownKeys. Bundles that include the merge/omit source walkers are 45 bytes larger minified.bcef104: A plain write made while an optimistic guess is out now waits for the async it needs, even when the memo that needs it is the guess's lane work. Before, that memo got the old async result alongside the new value. For example, a filter switch showed "closed" with the open rows until its fetch answered, both through a keyed projection and under a
<Loading on>boundary, which also dropped the guess from the screen. The screen now keeps what it showed, an armed<Loading>shows its fallback, and the switch lands with the fetch's answer.eef34fd: Fix two cases where a conditional written as a ternary behaved differently from
<Show>. At a component root,<>{c() ? a : b}</>now opens its branch at once under an action's optimistic guess, as<Show>does (Optimistically mounted component appears before its dynamic style is applied #3835). AnisPendingternary in an<Errored>fallback no longer keeps the first error's text after a reset when the source fails again.ebd6283: Two gate shapes S-58 says must match
<Show>now do ([2.0 / next] A second action that un-poisons a throwing memo chain, after the first action completed in the flush that errored the root and remounted the readers, wedges the flush: Potential Infinite Loop Detected (last staged node: computed) — async generator seed 7 case 1158 #4405, test(web): pin the probe-gated mount tear without Show's hop #4708 follow-up).latest()reader and the branch, the zombie's retry threw a fresh error that re-derived the live gate, and the live gate's retry next round re-derived the zombie again: "Potential Infinite Loop Detected" in dev and a hang in prod. A zombie's fate is the seam's (L2), so it throws the error it has.<Errored>around the branch's content made the content's effect a plain leaf, so it attached with its hole empty during the flight (F-2) through a hand-written gate.solid-js@2.0.0-rc.22
Patch Changes
cf839ea: Context providers no longer create an owner of their own: the provided value now sits on the two memos that resolve the provider's children, so each provider allocates one node and one bound function fewer.
c50abb6: A
dynamicmount of a live server component that switches arguments and comes back to its first call (a windowed view scrolling back to the slice the page was served with) shows that call again. The equals gate compared the incoming binding with the one the memo holds, which is the first resolution's, so the way back read as "nothing changed" and the mount stayed on the other address.A live connection cancelled before its body's
startarrived now reads as a death, and the loop reconnects. A remount replaying a warm store gives up on a row-op record by cancelling the new connection so the resume re-sends the hole whole; with nothing open yet, the end read as a completion and the mount was left with no live connection.e76279f: Dev now warns
OPTIMISTIC_WRITE_WHILE_LOADINGwhen an optimistic setter runs while its source, which has answered before, is loading a new question. The setter composes on the previous answer, and the new answer replaces the guess ([2.0 / next] A guess written while its source loads a new question runs over the previous question's answer #4795).32b4294: Fail renderToStream when the default serializer reports a synchronous error before the first flush, matching asynchronous failures. No HTML is sent, onCompleteAll is skipped, and createSSRResponse returns 500 when consuming the stream. An error an
<Errored>contained does not fail the render when it cannot be serialized: its record and the rejection of its source, deferStream or streamed, are sent as a plain Error with its message, the fallback stays, and the error hook hears the failure once. A rejection nothing contained still fails the render.9c917ea: A ref callback that reads a sync memo on a row mounted while an async memo is in flight no longer leaves that update held forever ([2.0 rc.14+] A ref that reads a memo on a row mounted during an async memo's flight leaves the update held forever (production builds only) #4767). Refs run in the attribute effect's commit half with no owner; a memo born into the hold has only a staged value, and an ownerless read of it threw
NotReadyError(A19 exception 1), which errored the effect mid-hold so the transaction never landed.runRefCallbacknow marks the read, andservereturns the staged value only when the ref's creating pass was born into that memo's hold (F-7); productionref()always goes throughrunRefCallbackso the mark is present outside dev too.7230c08: A ref callback (
ref={el => …}) now runs the way a render effect's callback runs at creation ([2.0 rc.21 / next] A non-keyed <Show>/<Match> branch hidden by an optimistic write throws a stale read from its ref on restore and halts reactivity #4761). It is untracked and runs in the context of the pass that creates the element, so its reads see what that pass is building. Before, it ran with no owner, so its reads were outside reads that saw the screen before the pass committed. A non-keyed<Show>/<Match>branch that an optimistic write had hidden could not come back: its ref read the narrowed accessor, got the old falsy condition, and threw a stale read that halted the app.A ref still owns nothing. In dev, creating a memo, effect or root inside it throws
PRIMITIVE_IN_EFFECT_CALLBACK, andonCleanupinside it throwsCLEANUP_IN_FORBIDDEN_SCOPE. Set those up in the factory that returns the ref, which runs in the component body. Writes,refresh, action calls andonFlushstay allowed in a ref, as in an effect callback.c8c5eb1: Server rendering only treats nodes the runtime made as finished markup.
ssr(),ssrElement()and the frames sink now stamp their nodes with theSymbol.for("solid.ssrNode")symbol (as$, a value no data can hold), and every insert position checks it instead of the object's shape. A plain object with atkey (ort,handp), such as one parsed from JSON, is data: it renders nothing and gets the dev warning UNRECOGNIZED_INSERT_VALUE, like any other plain object. The async-memo landing check (ASYNC_MEMO_ELEMENT) uses the same brand, so such data now serializes like other data instead of being refused. Server only; no client bytes.Updated dependencies [5755ddd]
Updated dependencies [cf32a50]
Updated dependencies [ce7b4bb]
Updated dependencies [aaf528d]
Updated dependencies [d476295]
Updated dependencies [f6b6737]
Updated dependencies [2789ca9]
Updated dependencies [db3d13d]
Updated dependencies [bc423eb]
Updated dependencies [5208944]
Updated dependencies [6751472]
Updated dependencies [5ecd72f]
Updated dependencies [4de85c2]
Updated dependencies [6b7474b]
Updated dependencies [dc33de6]
Updated dependencies [f00ce6f]
Updated dependencies [da402ca]
Updated dependencies [79b6541]
Updated dependencies [45498e3]
Updated dependencies [e0f31bc]
Updated dependencies [1bdd973]
Updated dependencies [0895916]
Updated dependencies [edeb5db]
Updated dependencies [a01fd92]
Updated dependencies [d00f055]
Updated dependencies [38b6f85]
Updated dependencies [4fe7532]
Updated dependencies [ccb438d]
Updated dependencies [78eaf88]
Updated dependencies [cd4de28]
Updated dependencies [e76279f]
Updated dependencies [8b7254a]
Updated dependencies [46a72c0]
Updated dependencies [abbb806]
Updated dependencies [6681c1b]
Updated dependencies [a8b8b67]
Updated dependencies [9c917ea]
Updated dependencies [7230c08]
Updated dependencies [9d4f077]
Updated dependencies [fb672ca]
Updated dependencies [e76279f]
Updated dependencies [b050983]
Updated dependencies [9de15ba]
Updated dependencies [d06e7a7]
Updated dependencies [c981680]
Updated dependencies [b3e9fb8]
Updated dependencies [bcef104]
Updated dependencies [eef34fd]
Updated dependencies [ebd6283]
@solidjs/universal@2.0.0-rc.22
Patch Changes
9c917ea: A ref callback that reads a sync memo on a row mounted while an async memo is in flight no longer leaves that update held forever ([2.0 rc.14+] A ref that reads a memo on a row mounted during an async memo's flight leaves the update held forever (production builds only) #4767). Refs run in the attribute effect's commit half with no owner; a memo born into the hold has only a staged value, and an ownerless read of it threw
NotReadyError(A19 exception 1), which errored the effect mid-hold so the transaction never landed.runRefCallbacknow marks the read, andservereturns the staged value only when the ref's creating pass was born into that memo's hold (F-7); productionref()always goes throughrunRefCallbackso the mark is present outside dev too.7230c08: A ref callback (
ref={el => …}) now runs the way a render effect's callback runs at creation ([2.0 rc.21 / next] A non-keyed <Show>/<Match> branch hidden by an optimistic write throws a stale read from its ref on restore and halts reactivity #4761). It is untracked and runs in the context of the pass that creates the element, so its reads see what that pass is building. Before, it ran with no owner, so its reads were outside reads that saw the screen before the pass committed. A non-keyed<Show>/<Match>branch that an optimistic write had hidden could not come back: its ref read the narrowed accessor, got the old falsy condition, and threw a stale read that halted the app.A ref still owns nothing. In dev, creating a memo, effect or root inside it throws
PRIMITIVE_IN_EFFECT_CALLBACK, andonCleanupinside it throwsCLEANUP_IN_FORBIDDEN_SCOPE. Set those up in the factory that returns the ref, which runs in the component body. Writes,refresh, action calls andonFlushstay allowed in a ref, as in an effect callback.Updated dependencies [cf839ea]
Updated dependencies [c50abb6]
Updated dependencies [e76279f]
Updated dependencies [32b4294]
Updated dependencies [9c917ea]
Updated dependencies [7230c08]
Updated dependencies [c8c5eb1]
@solidjs/web@2.0.0-rc.22
Patch Changes
366c0eb:
renderToStream().pipe()no longer throwsbuffer.flush is not a functionwhen the render is abandoned from inside its first write ([2.0 rc.21 / next] renderToStream: a render abandoned inside pipe's first write throws "buffer.flush is not a function" #4745). With a shell of 16384 characters or more, a pre-flush redirect increateSSRResponse, a sink whosewritethrows or asignalaborted from inside that write leftpipeflushing a buffer that had noflush, and the unhandled rejection ended the process under Node's default handling.90d1a51: A viewer that joins a running
broadcastis sent each live range once, as it shows now. Its snapshot used to carry the frame as it first rendered and then every changed hole whole again, so a late joiner downloaded a big live table twice (about 600 ms to join a 2,000-row table, now about 120 ms).3ce08e9: A string
classvalue no longer stores a property on the element when it is rendered on the client.className()cleared its applied-classes snapshot withnode._$classes = undefinedbefore every string write, which added an own property to each element the first time its class was set, even though only an objectclassvalue ever fills that snapshot. It now clears the snapshot only when one exists. Mounting 1,000 table rows with six string class bindings each allocates about 118 KB less (1,793 KB to 1,675 KB), and a uibench tree render is 5 to 10% faster. Behavior is unchanged. The hydrating path still seeds the snapshot as before.8506dbf: fix(web): a
deferStreamsource that rejects on the server hydrates as a rejection, soreset()refetches it on the client (Hydration: a rejected deferStream source is adopted as a value, so reset() shows the Error and never refetches #4747)54456c9: A live server component's attribute whose value is still pending at the top of the render (no
<Loading>around it) no longer writes the live-hole comment markers inside the tag or the attribute value (<div<!--lh:1--> style="…"<!--lh:/1-->>), which broke the element. The element keeps its attribute address, and the binding registers once the tag's pending values resolve, so later values update the attribute as anattrop.c50abb6: A
dynamicmount of a live server component that switches arguments and comes back to its first call (a windowed view scrolling back to the slice the page was served with) shows that call again. The equals gate compared the incoming binding with the one the memo holds, which is the first resolution's, so the way back read as "nothing changed" and the mount stayed on the other address.A live connection cancelled before its body's
startarrived now reads as a death, and the loop reconnects. A remount replaying a warm store gives up on a row-op record by cancelling the new connection so the resume re-sends the hole whole; with nothing open yet, the end read as a completion and the mount was left with no live connection.246a491:
insertno longer carries the portal host tagging in a bundle that renders no<Portal>: Portal installs it on first use. A hand-writteninsert(..., { host })outside Portal now needsinstallHostTagging()first.32b4294: Fail renderToStream when the default serializer reports a synchronous error before the first flush, matching asynchronous failures. No HTML is sent, onCompleteAll is skipped, and createSSRResponse returns 500 when consuming the stream. An error an
<Errored>contained does not fail the render when it cannot be serialized: its record and the rejection of its source, deferStream or streamed, are sent as a plain Error with its message, the fallback stays, and the error hook hears the failure once. A rejection nothing contained still fails the render.218fe4a: The DOM list reconciler no longer throws
NotFoundErrorwhen user code moved a list node past the end of its list and the same update removes or replaces that node. The append step used the node after the list as its anchor even after the pass had taken it out of the parent; it now falls back to the marker, or the end of the parent.dfb1812: The DOM list reconciler does less work for common small edits. A node moved from one end of a list to the other takes one DOM move, a list whose nodes did not change returns before reading the parent, and the window map is an index stamp on the new nodes instead of a
Map. On the Octane board js-framework's reorder operations take about 20% less time and a text hole beside sibling nodes updates about 13% faster. Bundles with the web runtime are 33 bytes smaller minified.b38d592: List reconciliation moves every connected node with
Element.moveBefore()where the browser has it, not only the node holding focus, and no longer usesreplaceChild()there. Moved rows stay connected, so focus and other node state survive any reorder, and a reorder places nodes instead of detaching and reattaching them: dbmon's 1,000-row sort drops from ~2.0 ms to ~0.75 ms, and shuffles and reverses get 3–7% faster. The per-passdocument.activeElementread is gone. New nodes and browsers withoutmoveBefore()keepinsertBefore()as before.9c917ea: A ref callback that reads a sync memo on a row mounted while an async memo is in flight no longer leaves that update held forever ([2.0 rc.14+] A ref that reads a memo on a row mounted during an async memo's flight leaves the update held forever (production builds only) #4767). Refs run in the attribute effect's commit half with no owner; a memo born into the hold has only a staged value, and an ownerless read of it threw
NotReadyError(A19 exception 1), which errored the effect mid-hold so the transaction never landed.runRefCallbacknow marks the read, andservereturns the staged value only when the ref's creating pass was born into that memo's hold (F-7); productionref()always goes throughrunRefCallbackso the mark is present outside dev too.7230c08: A ref callback (
ref={el => …}) now runs the way a render effect's callback runs at creation ([2.0 rc.21 / next] A non-keyed <Show>/<Match> branch hidden by an optimistic write throws a stale read from its ref on restore and halts reactivity #4761). It is untracked and runs in the context of the pass that creates the element, so its reads see what that pass is building. Before, it ran with no owner, so its reads were outside reads that saw the screen before the pass committed. A non-keyed<Show>/<Match>branch that an optimistic write had hidden could not come back: its ref read the narrowed accessor, got the old falsy condition, and threw a stale read that halted the app.A ref still owns nothing. In dev, creating a memo, effect or root inside it throws
PRIMITIVE_IN_EFFECT_CALLBACK, andonCleanupinside it throwsCLEANUP_IN_FORBIDDEN_SCOPE. Set those up in the factory that returns the ref, which runs in the component body. Writes,refresh, action calls andonFlushstay allowed in a ref, as in an effect callback.c8c5eb1: Server rendering only treats nodes the runtime made as finished markup.
ssr(),ssrElement()and the frames sink now stamp their nodes with theSymbol.for("solid.ssrNode")symbol (as$, a value no data can hold), and every insert position checks it instead of the object's shape. A plain object with atkey (ort,handp), such as one parsed from JSON, is data: it renders nothing and gets the dev warning UNRECOGNIZED_INSERT_VALUE, like any other plain object. The async-memo landing check (ASYNC_MEMO_ELEMENT) uses the same brand, so such data now serializes like other data instead of being refused. Server only; no client bytes.7b405e9: Add
setTrustedTypesPolicy(policy), so Solid renders on pages that enforcerequire-trusted-types-for 'script'. The app passes a Trusted Types policy it created, and the runtime assigns theTrustedHTMLthat policy returns, for compiled template markup, for the server HTML the frames client parses, and for thehtmltagged template's text decoding. On the server it is a no-op, so an isomorphic entry can call it. Nothing changes for apps that do not call it.b3731b0: A text value that shares its parent with other children (
<p>Count: {n()}</p>) no longer reads the text node's.databefore each write. The node remembers the last value written and later updates compare against that, which takes a signal-driven text update from about 0.59 µs to about 0.35 µs. The first write to a node still compares with the DOM. One behavior difference: if something outside Solid rewrites such a text node and the value then re-evaluates to what Solid last wrote, the text is no longer written back.Updated dependencies [cf839ea]
Updated dependencies [c50abb6]
Updated dependencies [e76279f]
Updated dependencies [32b4294]
Updated dependencies [9c917ea]
Updated dependencies [7230c08]
Updated dependencies [c8c5eb1]
board-example@0.0.1-rc.7
Patch Changes
canvas-example@0.0.1-rc.3
Patch Changes
server-dbmon-example@0.0.1-rc.6
Patch Changes
todos-server-example@0.0.1-rc.10
Patch Changes
test-integration@2.0.0-rc.22
Patch Changes