Repository navigation
fix(compiler): scope-wrap dynamic children holes in the ssr spread path - #540
Merged
ryansolid merged 2 commits intoJul 9, 2026
Merged
Conversation
The hole-owner-id-scopes change added the ssr generate's scope() wrap in
transformChildren (the template path) but never in createElement, the
spread-element path that renders through ssrElement. The dom generate
scope-wraps the matching insert accessor regardless of spread, so a shape
like <a {...props}>{children()}</a> reserved a hydration id slot on the
client but not on the server — every hydration key allocated after the
hole drifted and following siblings went unclaimed (duplicated DOM,
'unclaimed server-rendered node' warnings). Hit in practice upgrading
TanStack Router to Solid 2.0.0-beta.16, where every <Link> desynced the
ids of all its following siblings.
createElement now applies the same wrap as transformChildren: dynamic
children holes that can allocate hydration ids evaluate under their own
owner scope. Regression-tested end-to-end in the runtime hydration suite;
the new test fails with the exact sibling-unclaimed symptom when the wrap
is removed.
Co-Authored-By: Claude Fable 5 <[email protected]>
🦋 Changeset detectedLatest commit: 241ff76 The changes in this PR will be included in the next version bump. This PR includes changesets to release 5 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
Author
|
Might need a rust compiler change too? |
…rops
mergeProps with a function source creates a memo, which consumes a
hydration child id. The ssr generate evaluated mergeProps(...) in
ssrElement's argument position — before the element's own hydration key
was allocated — while the client claims the element via getNextElement
before applying the spread. The element's id shifted by one on the
server, the client re-created it instead of claiming, and later siblings
re-synced — hiding the drift behind a single duplicated element. Hit in
practice as TanStack Router's <title ref={...} {...attrs}> duplicating on
every hydration (the ref forces the compiler into the mergeProps path).
The ssr generate now defers the merge behind a thunk when hydratable,
and ssrElement allocates the hydration key before resolving function
props, matching the client's allocation order. The runtime regression
test fails with the exact unclaimed-element symptom when either half of
the fix is reverted.
Co-Authored-By: Claude Fable 5 <[email protected]>
ryansolid
added a commit
that referenced
this pull request
Jul 9, 2026
…iler Mirror #540 in the Rust ssr generate: scope-wrap dynamic children holes of spread elements and defer hydratable mergeProps behind a thunk so ssrElement allocates the element's hydration key before dynamic props run. Regenerates the ssr-hydratable fixtures and parity expectations against the updated babel output. Co-authored-by: Cursor <[email protected]>
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.
Summary
The hole-owner-id-scopes change added the ssr generate's
scope()wrap intransformChildren(the template path) but never increateElement, the spread-element path that renders throughssrElement. The dom generate scope-wraps the matching insert accessor regardless of spread, so a shape like<a {...props}>{children()}</a>reserved a hydration id slot on the client but not on the server — every hydration key allocated after the hole drifted and following siblings went unclaimed (duplicated DOM, "unclaimed server-rendered node" warnings).Hit in practice upgrading TanStack Router to Solid 2.0.0-beta.16, where every
<Link>desynced the ids of all its following siblings.Fix
createElementnow applies the same wrap astransformChildren: dynamic children holes that can allocate hydration ids evaluate under their own owner scope.Testing
Regression-tested end-to-end in the runtime hydration suite; the new test (
packages/runtime/test/ssr/hydrate-spread-scope.spec.js) fails with the exact sibling-unclaimed symptom when the wrap is removed.