Skip to content

Release RC packages (rc) - #4252

Open
github-actions[bot] wants to merge 1 commit into
nextfrom
changeset-release/next
Open

github-actions[bot] wants to merge 1 commit into
nextfrom
changeset-release/next

Conversation

@github-actions

@github-actions github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

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.

⚠️⚠️⚠️⚠️⚠️⚠️

next is currently in pre mode so this branch has prereleases rather than normal releases. If you want to exit prereleases, run changeset pre exit on next.

⚠️⚠️⚠️⚠️⚠️⚠️

Releases

@solidjs/babel-plugin@2.0.0-rc.19

Patch Changes

  • 8cff139: Evaluated negative and non-finite numbers (c={-1}, d={NaN}) are static again. Since Babel 8 support, evaluateAndInline built them with t.valueToNode, which gives -1 / 0 / 0 expressions rather than numeric literals, so they stopped being inlined into templates (SSR emitted ssrAttribute("c", -1) instead of c="-1") and diverged from @solidjs/compiler (the parity probes' "exotic literal holes"). They are now NumericLiteral nodes again, built directly where @babel/types 8's builder would reject the value; both Babel majors print them as before.
  • 55c7329: Support @babel/core 8 alongside 7: the peer range is now ^7.20.12 || ^8.0.0. SSR no longer reads Scope#uids (removed in Babel 8), evaluated negative or non-finite numbers are built with valueToNode, import() parsed as ImportExpression stays dynamic, and TSRX emits the AST shape of the running Babel major (type arguments, type parameter names, import(), enums, heritage). TSRX also keeps import() options and class method type parameters, which it dropped before.
  • 9e1edbc: A lone dynamic spread on an SSR element (<label {...props()} />) now defers behind a thunk like a spread beside other attributes, so it runs after the element's hydration key. A spread that created a memo shifted the element's key on the server only, and hydration missed the element ([2.0 rc.17] A lone spread runs before the element's hydration key on the server, after it on the client #4240).

@solidjs/compiler@2.0.0-rc.19

Patch Changes

  • ade599a: The Rust compiler core exports compile_program, an entry point that compiles an Oxc Program the caller has already built instead of source text. It is compile with the parse step split off: the program goes through the same dom / ssr / universal / dynamic back ends, with the same requireImportSource gate and coverage-pragma handling, so a frontend that produces an AST (rather than projecting to JSX text) gets the shared lowering and source maps on its own authored positions. source must be the program's source_text. Additive and Rust-only: compile and the Node transform() are unchanged (the shared back half is factored out of compile_inner; the TSRX route reaches it with its extracted stylesheet as before).
  • 838b74b: The Rust compiler core exports TSRX's scoped-CSS engine as solidjs_compiler::style, moved from src/tsrx/style/ to src/style/ so it is available without the tsrx feature: compile_style, compile_style_with_class_map_selectors, and their input and output types (StyleInput, StyleLocation, StyleKind, Element, ElementKind, ElementChild, Attribute, AttributeValue, StyleOutput, ClassMapEntry, StyleError). The engine already had no dependency on the TSRX frontend; exporting it lets another frontend (one that does not use TSRX at all) scope a <style> block over its own elements and get the same stylesheet and hash a .tsrx file gets. Additive and Rust-only: the TSRX route and the Node transform() are unchanged.
  • 0c6db49: The secondary passes (transformDirectives, the lazy and refresh passes, source names) accept a filename with any extension. They run on code that is already lowered to JavaScript, so the filename is metadata rather than a parser choice: a known extension still picks its dialect, and any other (App.rx, from another front end) is parsed as TSX instead of failing with "Unknown file extension". This matters for server functions, whose IDs hash the filename: a front end can now pass the module's real path, so the ID matches the one moduleForFunctionId computes for that module. The JSX transform itself is unchanged.
  • 9e1edbc: A lone dynamic spread on an SSR element (<label {...props()} />) now defers behind a thunk like a spread beside other attributes, so it runs after the element's hydration key. A spread that created a memo shifted the element's key on the server only, and hydration missed the element ([2.0 rc.17] A lone spread runs before the element's hydration key on the server, after it on the client #4240).
  • 4b836ab: Validate SSR templates rooted at an SVG or MathML element (such as <image> or <g> under control flow, in a fragment, or as a component root) inside their <svg>/<math> owner, as DOM templates already are, so valid SVG partials no longer fail the validate check.

@solidjs/diagnostics@2.0.0-rc.19

Patch Changes

@solidjs/element@2.0.0-rc.19

Patch Changes

@solidjs/h@2.0.0-rc.19

Patch Changes

@solidjs/html@2.0.0-rc.19

Patch Changes

  • 916e0eb: Decode character references in static attribute values. placeholder="Search&hellip;" rendered the literal &hellip;, an href with &amp; kept it in the URL, and components received static props like "a &amp; b" undecoded. Values are now decoded once with the HTML parser's quoted-attribute rules, as text children already were.
  • Updated dependencies [2c9fdd9]
  • Updated dependencies [2a0da2f]
  • Updated dependencies [f5cf675]
  • Updated dependencies [542ff6f]
  • Updated dependencies [2f7dc84]
  • Updated dependencies [2c9fdd9]
  • Updated dependencies [e0e4224]
  • Updated dependencies [5601848]
  • Updated dependencies [88ea86c]
  • Updated dependencies [4eb570e]
  • Updated dependencies [e8b0b15]
    • @solidjs/web@2.0.0-rc.19

@solidjs/signals@2.0.0-rc.19

Patch Changes

  • 2a0da2f: fix(web): refuse an async memo that resolves to an element ([2.0.0-rc.18] renderToStream: one value seroval cannot serialize leaves every value in its hydration batch unresolved #4242)

    On the server, an async memo (or async iterable source) whose value is rendered output — JSX, a component's result, a <Loading>/<Errored> boundary — can no longer reach the hydration serializer. A boundary's output failed in seroval, so its record never resolved and the hydrating client waited on the memo forever (streamed, the boundary reverted to its fallback); a template object crossed as data, duplicating the markup, and streamed the client could not insert it (UNRECOGNIZED_INSERT_VALUE). The memo now rejects where its value lands, with the new diagnostic ASYNC_MEMO_ELEMENT (recorded on the observe channel; the dev message says what to do instead, other tiers carry the code), and its boundary contains the error like any render error: the nearest <Errored> renders its fallback and the client hydrates it; with none, the <Loading> fragment rejects and the client renders the subtree. Return data from the async memo and render the JSX from it. Ordinary data is never refused (only plain objects in the SSR template shape, boundary outputs and fragment arrays holding them count as rendered output), and content that never hydrates (<NoHydration>) is untouched.

    Also, a fragment failing while a boundary registered under an undefined key (one created inside an async memo's continuation) is pending no longer fails the whole request in renderToStream.

  • 0847122: Two mounts under one boundary, made in separate flushes, keep their holds independent (S-5 rows 1′–3′, D-4, [2.0 / next] Two mounts under one error boundary merge their holds though they were made in separate flushes (S-5, D-4) #4283). A boundary's tree and output are structure, not a user derivation of its content: like the render effect that flattens the same children without a boundary, they read a hold they are not part of as committed and are re-derived at its landing, and a re-pass of one outside its hold's flush publishes mainline instead of re-joining that hold and merging it with the next flush's. <Errored> and <Loading> (with or without on) around two <Show>s, each over its own hold, now reveal each branch at its own hold's landing. A re-arm's swap is still the change's work: while it is, the output joins the change (D-13).

  • 0090fe3: Fix: a streamed <Loading> claimed after a client write changed a shell memo it reads now shows the client's value. A hydrated memo adopted while its server answer was still streaming had no snapshot, so once a client write took its compute over, the boundary's claim read the client's value while adopting the server's markup — and kept the server's text (or attribute) for good, since nothing re-ran the binding. The memo's server answer is now its snapshot when it lands, even when the write already superseded it: the claim reads what the markup shows and replays the client's value at its release, as for a written signal. If the client's recompute is still in flight when the boundary resumes, the claim is served the snapshot instead of going pending, so the boundary keeps the server's content (no fallback over it, no detached nodes, no lost queued click) until the client's value lands.

  • 0dd40b2: Release deferred flight bookkeeping when iterator setup or the initial pull throws, so pending verdicts clear and truth readers receive the current error.

  • f811097: A derived store's per-key isPending now reads true while the derive re-asks under a Loading boundary that has shown content, when the verdict is read in the same computation as the value (${state.a} ${isPending(() => state.a)}). The derive's first flight left a commit-beneath-a-flight mark that its setter landing never cleared, so the next re-ask suspended the verdict reader to the boundary (which kept the stale screen with isPending false) instead of serving it the committed value with isPending true, as an async memo does. ([2.0 / next] A derived store's per-key isPending reads false under a Loading that has shown content (D-30, S-37) #4269)

  • 8b34f22: An error boundary that caught an error rethrown from an inner boundary's fallback now recovers when the inner content does: switching the inner boundary back to its content disposes the fallback that threw, and the outer boundary now drops that error and shows its content again in the same flush, instead of keeping its fallback until some later error re-rendered it ([2.0 / next] An outer error boundary that caught a rethrow from an inner fallback does not recover #4270).

  • 2d9c9aa: Drain pending computations after disposal, releasing retired roots while idle.

  • c1009e5: A render effect that reads latest(s) before an async value that has never shown now holds its mount the same way the reverse read order does: an earlier latest() read no longer turns the later unready read into waiting lane work, so a newly mounted branch (for example under <Show>) stays unpublished until the value lands instead of appearing with an empty slot (S-39, D-28) ([2.0 / next] A reader whose first read is latest(s) publishes an empty slot instead of holding the mount (S-39, D-28) #4275).

  • 6ca7e8d: latest() of an optimistic value now shows the guess beside the held screen however reads are grouped into render effects ([2.0 / next] A held optimistic lane holds per render effect: latest(x) in its own JSX hole shows the guess beside held content (D-25) #4284). When a guess's lane is held on a downstream async derivation, a render effect that reads the guess and latest(guess) together no longer parks with the lane and freezes the latest() read: like split effects, it shows 1 x1 / 5 (the committed value and its derivation beside the guess) and 5 x5 / 5 when the derivation lands. The lane still holds the guess until its derivation lands; an unblocked lane costs no extra pass.

  • 3b6f839: A re-armed Loading boundary (on) whose fallback reads pending data through a render effect — any compiled JSX fallback, such as <p>Meta {meta()}</p> — no longer holds the new content's reveal when the content lands first: a fallback the screen never showed is disposed as soon as the content replaces it, so the content shows as soon as it lands and the fallback is never seen, as it already did when the fallback read the data directly ([2.0 / next] A render effect in a re-armed Loading fallback holds the content's reveal (S-22 row 3′) #4268).

  • 4ea2f49: UNSTABLE_MEMO_OUTPUT no longer reports the memo merge() creates for a function source, such as a compiled conditional component spread (<Child {...(on() ? { tone } : {})} />). No one can pass that memo equals, so the warning had no fix (UNSTABLE_MEMO_OUTPUT fires on the memo merge() creates for a function source (<C {...cond() ? { a } : {}} />); its advice (equals) cannot be applied to that memo #4256). In observe builds the memo is now named merge. Production output is unchanged.

  • 1d6c40f: Add onFlush(fn): runs fn once right after the pending flush, before paint, without waiting on async work. A write made there is its own update, so it is not held by async work another write in the same frame started (a menu closing while the consumer's onSelect navigates). Meant for event handlers and effect callbacks; dev warns (ON_FLUSH_IN_OWNED_SCOPE) in a component body or computation. Tree-shakes when unused.

  • 1212b77: A derived store (createProjection or createStore(fn)) over a memo now follows the memo after it has shown a value: when the memo goes pending again, isPending on the store's keys reports it, and when the memo later throws, the error reaches the error boundary instead of the store silently keeping its last value. ([2.0 / next] A keyed createProjection over a memo stops reporting pending and swallows later errors #4271)

  • e509ad1: A keyed derived store over an async memo follows every landing ([2.0 / next] Regression from #4280: a keyed projection's per-row memos miss every landing after the first #4305): when the source goes pending, the readers of the store's keys wait on the derive itself, so a reader whose value a landing leaves unchanged (a memo per row under mapArray/<For>) is released by the landing instead of holding the first one forever. The same holds when the derive re-runs while its source is pending.

  • 253561e: A memo whose first read rejected stays uninitialized when it is re-asked: an isPending pass and latest() throw NotReady until a value lands instead of reading undefined ([2.0] A memo whose first read rejected reads undefined (not NotReady) in a verdict pass while it is re-asked #4244).

  • e0e4224: A served answer's arrival during hydration no longer swallows a client write made in the same flush. Writes made before the arrival flush first, outside hydration's own pass, and a write made during it (an effect's, a later round of the flush) makes a node it reaches compute, so the node shows the written value instead of re-serving the server's answer. @solidjs/signals exports its internal flush-round counter (clock) for this.

  • c225400: IMMUTABLE_UPDATE_IN_STORE no longer reports an array index that now holds an item the array already had, such as the next item shifted down by an in-place splice (the repair the diagnostic recommends). Before, if the removed item and its neighbour shared at least half of their leaves, the move was reported as a spread-copy replacement ([2.0] IMMUTABLE_UPDATE_IN_STORE false positive when an in-place splice shifts the next item into the removed index #4262). A fresh copy assigned to an index is still reported. Production output is unchanged.

  • 87934c1: Smaller bundles: builds without the optimistic-store, reveal-order or lane hook modules drop their dead branches, and the [2.0 / next] Hydration: an error boundary hydrated in its error state never recovers #4273/[2.0 / next] A reader whose first read is latest(s) publishes an empty slot instead of holding the mount (S-39, D-28) #4275 fixes share existing paths.

solid-js@2.0.0-rc.19

Patch Changes

  • 2a0da2f: fix(web): refuse an async memo that resolves to an element ([2.0.0-rc.18] renderToStream: one value seroval cannot serialize leaves every value in its hydration batch unresolved #4242)

    On the server, an async memo (or async iterable source) whose value is rendered output — JSX, a component's result, a <Loading>/<Errored> boundary — can no longer reach the hydration serializer. A boundary's output failed in seroval, so its record never resolved and the hydrating client waited on the memo forever (streamed, the boundary reverted to its fallback); a template object crossed as data, duplicating the markup, and streamed the client could not insert it (UNRECOGNIZED_INSERT_VALUE). The memo now rejects where its value lands, with the new diagnostic ASYNC_MEMO_ELEMENT (recorded on the observe channel; the dev message says what to do instead, other tiers carry the code), and its boundary contains the error like any render error: the nearest <Errored> renders its fallback and the client hydrates it; with none, the <Loading> fragment rejects and the client renders the subtree. Return data from the async memo and render the JSX from it. Ordinary data is never refused (only plain objects in the SSR template shape, boundary outputs and fragment arrays holding them count as rendered output), and content that never hydrates (<NoHydration>) is untouched.

    Also, a fragment failing while a boundary registered under an undefined key (one created inside an async memo's continuation) is pending no longer fails the whole request in renderToStream.

  • 0090fe3: Fix: a streamed <Loading> claimed after a client write changed a shell memo it reads now shows the client's value. A hydrated memo adopted while its server answer was still streaming had no snapshot, so once a client write took its compute over, the boundary's claim read the client's value while adopting the server's markup — and kept the server's text (or attribute) for good, since nothing re-ran the binding. The memo's server answer is now its snapshot when it lands, even when the write already superseded it: the claim reads what the markup shows and replays the client's value at its release, as for a written signal. If the client's recompute is still in flight when the boundary resumes, the claim is served the snapshot instead of going pending, so the boundary keeps the server's content (no fallback over it, no detached nodes, no lost queued click) until the client's value lands.

  • ee94440: Hydration keeps a client-only boundary's served fallback ([2.0 / next] Hydration: a client-only (ssrSource: "client") memo's served Loading fallback is dropped and rebuilt #4286). A <Loading> whose content reads a bare ssrSource: "client" source is served as its fallback plus the "$$f" marker; the client hydrated that fallback, then resumed by re-running the boundary, and when the content suspended on the question it now asks, the new boundary built a second fallback and dropped the served one (losing focus, selection or a running animation in it). The "$$f" route now creates the loading boundary once, at hydration: its content waits on the resume and its fallback hydrates the served one (built at the boundary's id, as the server built it), so content that suspends after the resume keeps the hydrated fallback until it can show.

  • f5cf675: An <Errored> around a <Loading> whose async read fails during a streamed render now shows its fallback in the server HTML outside server components too, and the client adopts it. Before, the boundary's HTML was empty until hydration (neither the loading nor the error fallback), and the hydrating client rendered the failed boundary from scratch: it asked again and showed the loading fallback. Now, when the <Loading> is all of the <Errored>'s content, the server draws the error fallback in its place (in the shell, or in the streamed fragment after the shell) and serializes the error at the <Errored>, so a client that hydrates after the failure arrived claims that markup and adopts its data without asking again, and recovers when the content's inputs change, as for any hydrated failure ([2.0 / next] Hydration: an error boundary hydrated in its error state never recovers #4273). A client that hydrated before the failure arrived renders it once, with nothing of the server's swap left beside it. With markup between the two boundaries the server still leaves the position blank and the client renders the failure ([2.0 / next] SSR: a boundary that fails through an async read renders no error fallback outside server-component scope, and hydration asks again #4287).

  • 8f1d9d2: Server: when an <Errored> renders its fallback for a <Loading> that failed after the shell, and a hole in that fallback rejects while the server waits for it, the rejection now goes to the next boundary up, as it does when a fallback throws synchronously. Inside a pending outer <Loading>, that outer fragment fails; under an outer <Errored> whose whole content is that position, the outer fallback is drawn there and the client adopts it. Before, the region streamed blank and the hydrating client halted (Errored fallback whose async hole rejects is dropped inside a pending outer Loading #4316). A synchronous throw in that fallback no longer writes an error record for an outer <Errored> without sending its fallback.

    The server's wait for that fallback now stops after the same pass budget as the <Loading> resume loop and then streams what it has. It also stops as soon as the render is torn down, for example when the request is aborted (Server wait for an Errored fallback's async holes has no pass limit or abort check #4317).

  • 8f1d9d2: An <Errored> whose fallback fails while rendering (a hole that rejects, or a synchronous throw) now passes that failure to the enclosing boundary on the server, in the shell as well as in a streamed fragment. An outer <Errored> draws its fallback in place of the region, and with none the request fails. Before, the region was sent blank, with the errors recorded and no markup for them.

  • 0856fee: An <Errored> boundary hydrated in the error state the server rendered now recovers. Before, hydration threw the server's error without running the content, so the boundary tracked nothing and stayed on the fallback until reset(), even after the failed content's inputs changed. Now the content runs during hydration, reading its server data without refetching but claiming no DOM, while the fallback claims the server's markup. If the content fails on the client, the boundary holds that client error and recovers when the content's inputs change. If the error only happened on the server, the server's fallback and error stay up until reset() is called or the content re-runs ([2.0 / next] Hydration: an error boundary hydrated in its error state never recovers #4273).

  • 542ff6f: An <Errored> whose fallback reads async data, around a <Loading> that fails after the shell, now streams its fallback once that data is ready, and a client hydrating after it arrived claims it. Before, the failure landed while the fallback's read was still pending, so the server had no markup for it. On its own, the boundary swapped to a blank and the client rendered the failure itself, asking for the failed read again. Inside an outer <Loading> still pending, the outer fragment arrived with the Errored region blank, and the client hydrated against the blank with warnings and showed nothing there. Now the failure waits for the fallback, as a swap to a fallback waits for the fallback to be ready: the loading placeholder stays until the finished fallback replaces it (carried by the outer fragment when that is still pending), and the error is serialized with it (Errored fallback with an async hole is dropped inside a pending outer Loading (SSR streaming) #4306).

  • 2c9fdd9: A boundary whose server render failed is rendered fresh on the client while adopting the server's records. Inside that render, a <Dynamic> tag now creates its element instead of throwing a hydration mismatch, and a <Portal> mounts. Hydration also completes when the adopted error has no client boundary to catch it.

  • e0e4224: A client hydrating mid-stream no longer asks again for an async read whose server answer was an error, nor flashes back to the <Loading> fallback after the failure showed ([2.0 / next] SSR: a boundary that fails through an async read renders no error fallback outside server-component scope, and hydration asks again #4287, Errored fallback with an async hole is dropped inside a pending outer Loading (SSR streaming) #4306). The content of a hydrated failure (a hydrated <Errored>'s content run, or a rejected fragment's fresh render over the <Errored> fallback the server drew) reads a shell memo a cycle after its error landed, and a later tracked read retries an errored async node; the serialized-value latch took that rerun for a client write and computed. Inside such a content run the rerun now re-serves the server's answer and arms nothing. A rejected fragment with no outcome streams an empty template (it was a lone space), so the nodes its swap lists are the server's outcome alone.

  • e0e4224: A memo that adopted its server answer no longer asks again when the server's answer for one of its sources arrives mid-stream. Hydrated mid-stream, an async shell memo b reading another, a, re-ran when a's server value landed, and the serialized-value latch took that rerun for a client write and computed b. The arrival of a served answer, with the flush that carries it, is now hydration's own pass (as a hydrated failure's content run is): a latched node re-running there re-serves its own answer and arms nothing. Only a client write makes it compute.

  • 1d6c40f: Add onFlush(fn): runs fn once right after the pending flush, before paint, without waiting on async work. A write made there is its own update, so it is not held by async work another write in the same frame started (a menu closing while the consumer's onSelect navigates). Meant for event handlers and effect callbacks; dev warns (ON_FLUSH_IN_OWNED_SCOPE) in a component body or computation. Tree-shakes when unused.

  • 8f1d9d2: Server: a <Loading> that fails after the shell while its fragment waits inside an outer <Loading> that is still pending no longer arrives as a blank region reported as a success. The failure now goes to the nearest enclosing boundary, as it does when the same read fails inside the outer <Loading>'s own render. An <Errored> between them draws its fallback in the outer fragment, the client adopts it, and its error is serialized with it. With no <Errored> between them, the outer fragment fails, and an <Errored> whose whole content is that outer <Loading> draws its fallback there. This also covers an <Errored> fallback that fails in that position. Before, the client hydrated the blank region and either halted or rendered nothing there (Errored fallback whose async hole rejects is dropped inside a pending outer Loading #4316).

  • 6d6f03f: <Repeat> with element (non-function) children no longer builds each row twice. It read the children getter once to check for a function and again for the value, so every row's JSX ran twice and its refs fired twice ([2.0 / next] Repeat in non-callback form executes children twice #4296).

  • e0e4224: A served answer's arrival during hydration no longer swallows a client write made in the same flush. Writes made before the arrival flush first, outside hydration's own pass, and a write made during it (an effect's, a later round of the flush) makes a node it reaches compute, so the node shows the written value instead of re-serving the server's answer. @solidjs/signals exports its internal flush-round counter (clock) for this.

  • 87934c1: Smaller bundles: builds without the optimistic-store, reveal-order or lane hook modules drop their dead branches, and the [2.0 / next] Hydration: an error boundary hydrated in its error state never recovers #4273/[2.0 / next] A reader whose first read is latest(s) publishes an empty slot instead of holding the mount (S-39, D-28) #4275 fixes share existing paths.

  • 2c9fdd9: Hydration never asks again for what the server sent, even when a streamed boundary's fragment rejects with no outcome (no <Errored> on the server could draw the failure). The client still renders that fragment fresh, so its graph is created, but every read in it now claims its serialized record: reads the server resolved take their values, and a read whose record is an error throws that error to the nearest client boundary, or is an uncaught error when there is none. Only reads with no record, such as those cut off by a truncated stream, compute. Recovery comes from a real input change or a boundary's reset(), as for any hydrated failure.

  • Updated dependencies [2a0da2f]

  • Updated dependencies [0847122]

  • Updated dependencies [0090fe3]

  • Updated dependencies [0dd40b2]

  • Updated dependencies [f811097]

  • Updated dependencies [8b34f22]

  • Updated dependencies [2d9c9aa]

  • Updated dependencies [c1009e5]

  • Updated dependencies [6ca7e8d]

  • Updated dependencies [3b6f839]

  • Updated dependencies [4ea2f49]

  • Updated dependencies [1d6c40f]

  • Updated dependencies [1212b77]

  • Updated dependencies [e509ad1]

  • Updated dependencies [253561e]

  • Updated dependencies [e0e4224]

  • Updated dependencies [c225400]

  • Updated dependencies [87934c1]

    • @solidjs/signals@2.0.0-rc.19

@solidjs/universal@2.0.0-rc.19

Patch Changes

@solidjs/web@2.0.0-rc.19

Patch Changes

  • 2c9fdd9: A streamed boundary that fails on the server can leave nested reads still pending. The server abandons those reads, and their records used to settle as undefined, which the client's fresh render of the failed fragment would then adopt as the server's answer. The server now unregisters abandoned records, so those reads compute on the client. The fresh render also spends an id on each element's hydration key, as the server did, so its reads line up with the server's records by id.

  • 2a0da2f: fix(web): refuse an async memo that resolves to an element ([2.0.0-rc.18] renderToStream: one value seroval cannot serialize leaves every value in its hydration batch unresolved #4242)

    On the server, an async memo (or async iterable source) whose value is rendered output — JSX, a component's result, a <Loading>/<Errored> boundary — can no longer reach the hydration serializer. A boundary's output failed in seroval, so its record never resolved and the hydrating client waited on the memo forever (streamed, the boundary reverted to its fallback); a template object crossed as data, duplicating the markup, and streamed the client could not insert it (UNRECOGNIZED_INSERT_VALUE). The memo now rejects where its value lands, with the new diagnostic ASYNC_MEMO_ELEMENT (recorded on the observe channel; the dev message says what to do instead, other tiers carry the code), and its boundary contains the error like any render error: the nearest <Errored> renders its fallback and the client hydrates it; with none, the <Loading> fragment rejects and the client renders the subtree. Return data from the async memo and render the JSX from it. Ordinary data is never refused (only plain objects in the SSR template shape, boundary outputs and fragment arrays holding them count as rendered output), and content that never hydrates (<NoHydration>) is untouched.

    Also, a fragment failing while a boundary registered under an undefined key (one created inside an async memo's continuation) is pending no longer fails the whole request in renderToStream.

  • f5cf675: An <Errored> around a <Loading> whose async read fails during a streamed render now shows its fallback in the server HTML outside server components too, and the client adopts it. Before, the boundary's HTML was empty until hydration (neither the loading nor the error fallback), and the hydrating client rendered the failed boundary from scratch: it asked again and showed the loading fallback. Now, when the <Loading> is all of the <Errored>'s content, the server draws the error fallback in its place (in the shell, or in the streamed fragment after the shell) and serializes the error at the <Errored>, so a client that hydrates after the failure arrived claims that markup and adopts its data without asking again, and recovers when the content's inputs change, as for any hydrated failure ([2.0 / next] Hydration: an error boundary hydrated in its error state never recovers #4273). A client that hydrated before the failure arrived renders it once, with nothing of the server's swap left beside it. With markup between the two boundaries the server still leaves the position blank and the client renders the failure ([2.0 / next] SSR: a boundary that fails through an async read renders no error fallback outside server-component scope, and hydration asks again #4287).

  • 542ff6f: An <Errored> whose fallback reads async data, around a <Loading> that fails after the shell, now streams its fallback once that data is ready, and a client hydrating after it arrived claims it. Before, the failure landed while the fallback's read was still pending, so the server had no markup for it. On its own, the boundary swapped to a blank and the client rendered the failure itself, asking for the failed read again. Inside an outer <Loading> still pending, the outer fragment arrived with the Errored region blank, and the client hydrated against the blank with warnings and showed nothing there. Now the failure waits for the fallback, as a swap to a fallback waits for the fallback to be ready: the loading placeholder stays until the finished fallback replaces it (carried by the outer fragment when that is still pending), and the error is serialized with it (Errored fallback with an async hole is dropped inside a pending outer Loading (SSR streaming) #4306).

  • 2f7dc84: First mounts of a multi-node insert skip reconcileArrays' diff setup (spa-navigation mounts ~3%). The once-per-pass focus read from feat(web): keep focus on a moved node with moveBefore() (#3997) #4261 still applies, so a focused node arriving from another list keeps its focus.

  • 2c9fdd9: A boundary whose server render failed is rendered fresh on the client while adopting the server's records. Inside that render, a <Dynamic> tag now creates its element instead of throwing a hydration mismatch, and a <Portal> mounts. Hydration also completes when the adopted error has no client boundary to catch it.

  • e0e4224: A client hydrating mid-stream no longer asks again for an async read whose server answer was an error, nor flashes back to the <Loading> fallback after the failure showed ([2.0 / next] SSR: a boundary that fails through an async read renders no error fallback outside server-component scope, and hydration asks again #4287, Errored fallback with an async hole is dropped inside a pending outer Loading (SSR streaming) #4306). The content of a hydrated failure (a hydrated <Errored>'s content run, or a rejected fragment's fresh render over the <Errored> fallback the server drew) reads a shell memo a cycle after its error landed, and a later tracked read retries an errored async node; the serialized-value latch took that rerun for a client write and computed. Inside such a content run the rerun now re-serves the server's answer and arms nothing. A rejected fragment with no outcome streams an empty template (it was a lone space), so the nodes its swap lists are the server's outcome alone.

  • 5601848: The focused node keeps focus when the runtime moves it, where the browser has Element.moveBefore() (Keep element state when the runtime moves a node (moveBefore() and not detaching what is re-inserted) #3997). List reconciliation moves the node that holds document.activeElement with moveBefore(), so a focused row survives a reorder, and a move into a list that updates before the one it leaves. While focus is in the list, the reconcile's replaceChild path inserts instead, leaving the old row in place until the pass places it. Focus is read once per pass, and not at all without moveBefore() or with focus on the body; every other node keeps plain insertBefore(), so reorders cost the same as before. Browsers without moveBefore() behave as before, with no focus restore. Array inserts into an empty slot now go through the same reconcile.

  • 88ea86c: Each event replayed after hydration is its own instant, as it would have been live ([2.0 / next] Hydration: events replayed by runHydrationEvents share one flush, so two clicks on a counter bump it once #4285). runHydrationEvents now flushes after every replayed event, so a handler reads the writes of the events before it: two clicks on a counter queued before the client loaded bump it twice, not once.

  • 4eb570e: Avoid retaining the first value-bound select and its form through the shared option-insertion hook.

  • e8b0b15: renderToStream: a value that fails to serialize no longer leaves the other pre-shell hydration values pending on the client ([2.0.0-rc.18] renderToStream: one value seroval cannot serialize leaves every value in its hydration batch unresolved #4242). Pending promises registered before the shell (async sources and Loading boundaries' <key>_fr completion flags) were handed to seroval as one object write. Since seroval 1.7, a value that fails to serialize ends the write it belongs to, so one failure stopped every value in that write. An async memo that resolves to an element, such as a nested <Loading>, left both boundaries unresolved and hydration never finished. The stubs are still held until the shell and handed over at the same point, in the same order, but each is now its own keyed write, so a failure only affects its own key, as on rc.17.

  • Updated dependencies [2a0da2f]

  • Updated dependencies [0090fe3]

  • Updated dependencies [ee94440]

  • Updated dependencies [f5cf675]

  • Updated dependencies [8f1d9d2]

  • Updated dependencies [8f1d9d2]

  • Updated dependencies [0856fee]

  • Updated dependencies [542ff6f]

  • Updated dependencies [2c9fdd9]

  • Updated dependencies [e0e4224]

  • Updated dependencies [e0e4224]

  • Updated dependencies [1d6c40f]

  • Updated dependencies [8f1d9d2]

  • Updated dependencies [6d6f03f]

  • Updated dependencies [e0e4224]

  • Updated dependencies [87934c1]

  • Updated dependencies [2c9fdd9]

    • solid-js@2.0.0-rc.19

board-example@0.0.1-rc.4

Patch Changes

canvas-example@0.0.1-rc.0

Patch Changes

server-dbmon-example@0.0.1-rc.3

Patch Changes

todos-server-example@0.0.1-rc.7

Patch Changes

test-integration@2.0.0-rc.19

Patch Changes

  • Updated dependencies [2c9fdd9]
  • Updated dependencies [2a0da2f]
  • Updated dependencies [8cff139]
  • Updated dependencies [55c7329]
  • Updated dependencies [0847122]
  • Updated dependencies [0090fe3]
  • Updated dependencies [ee94440]
  • Updated dependencies [0dd40b2]
  • Updated dependencies [f811097]
  • Updated dependencies [8b34f22]
  • Updated dependencies [f5cf675]
  • Updated dependencies [8f1d9d2]
  • Updated dependencies [8f1d9d2]
  • Updated dependencies [0856fee]
  • Updated dependencies [542ff6f]
  • Updated dependencies [2f7dc84]
  • Updated dependencies [2c9fdd9]
  • Updated dependencies [916e0eb]
  • Updated dependencies [e0e4224]
  • Updated dependencies [e0e4224]
  • Updated dependencies [2d9c9aa]
  • Updated dependencies [c1009e5]
  • Updated dependencies [6ca7e8d]
  • Updated dependencies [3b6f839]
  • Updated dependencies [9e1edbc]
  • Updated dependencies [4ea2f49]
  • Updated dependencies [5601848]
  • Updated dependencies [1d6c40f]
  • Updated dependencies [8f1d9d2]
  • Updated dependencies [1212b77]
  • Updated dependencies [e509ad1]
  • Updated dependencies [253561e]
  • Updated dependencies [6d6f03f]
  • Updated dependencies [88ea86c]
  • Updated dependencies [4eb570e]
  • Updated dependencies [e0e4224]
  • Updated dependencies [c225400]
  • Updated dependencies [e8b0b15]
  • Updated dependencies [87934c1]
  • Updated dependencies [2c9fdd9]
  • Updated dependencies [bae59bd]
    • @solidjs/web@2.0.0-rc.19
    • solid-js@2.0.0-rc.19
    • @solidjs/signals@2.0.0-rc.19
    • @solidjs/babel-plugin@2.0.0-rc.19
    • @solidjs/html@2.0.0-rc.19
    • @solidjs/universal@2.0.0-rc.19
    • @solidjs/h@2.0.0-rc.19

@github-actions
github-actions Bot force-pushed the changeset-release/next branch 30 times, most recently from 18aa4ba to 6c1f51e Compare October 27, 2026 07:19
@github-actions
github-actions Bot force-pushed the changeset-release/next branch 3 times, most recently from 64e668c to ef1baad Compare October 27, 2026 16:06
@github-actions
github-actions Bot force-pushed the changeset-release/next branch from ef1baad to bd058e8 Compare October 27, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants