fix(solid-router): resolve defaultNotFoundComponent at render time to avoid hydration desync#7734
Conversation
… avoid hydration desync Previously defaultNotFoundComponent was applied by lazily mutating the boundary route's options.notFoundComponent when a notFound was handled. Route objects are module singletons shared across server requests, so once the server handled any 404, later SSRs of valid URLs wrapped the match in a CatchNotFound boundary the freshly-hydrating client doesn't render, shifting hydration keys and leaving the subtree unclaimed (visible but inert DOM). Resolve defaultNotFoundComponent at render time in Match.tsx so the boundary structure is deterministic on both server and client, and add an e2e regression test.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit 85f092a
☁️ Nx Cloud last updated this comment at |
Merging this PR will improve performance by 84.75%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | ssr request loop (react) |
330.5 ms | 81.2 ms | ×4.1 |
| ⚡ | Simulation | client-side navigation loop (solid) |
72.6 ms | 42.7 ms | +70.17% |
| ⚡ | Simulation | ssr request loop (vue) |
420.3 ms | 286.8 ms | +46.54% |
| ⚡ | Simulation | ssr request loop (solid) |
174.6 ms | 152.2 ms | +14.74% |
| 🆕 | Simulation | ssr not-found (vue) |
N/A | 168.8 ms | N/A |
| 🆕 | Simulation | ssr redirect (vue) |
N/A | 68.4 ms | N/A |
| 🆕 | Simulation | ssr head (vue) |
N/A | 325.1 ms | N/A |
| 🆕 | Simulation | ssr loaders (vue) |
N/A | 136.6 ms | N/A |
| 🆕 | Simulation | ssr selective (vue) |
N/A | 139.8 ms | N/A |
| 🆕 | Simulation | ssr server-fn GET (vue) |
N/A | 74.5 ms | N/A |
| 🆕 | Simulation | ssr server-fn POST (vue) |
N/A | 71.4 ms | N/A |
| 🆕 | Simulation | ssr server-route middleware (vue) |
N/A | 63.3 ms | N/A |
| 🆕 | Simulation | ssr server-route (vue) |
N/A | 60.7 ms | N/A |
| 🆕 | Simulation | ssr streaming deferred (vue) |
N/A | 104.9 ms | N/A |
| 🆕 | Simulation | ssr assets inline-css cdn (vue) |
N/A | 187.6 ms | N/A |
| 🆕 | Simulation | ssr assets linked-css control (vue) |
N/A | 214.1 ms | N/A |
| 🆕 | Simulation | ssr before-load chain (vue) |
N/A | 184 ms | N/A |
| 🆕 | Simulation | ssr control-flow error 500 (vue) |
N/A | 198.2 ms | N/A |
| 🆕 | Simulation | ssr control-flow route headers (vue) |
N/A | 212.5 ms | N/A |
| 🆕 | Simulation | ssr control-flow unmatched 404 (vue) |
N/A | 189.8 ms | N/A |
| ... | ... | ... | ... | ... | ... |
ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing brenelz:fix/solid-router-default-not-found-hydration (85f092a) with solid-router-v2-pre (67a9040)1
Footnotes
f9b0e57
into
TanStack:solid-router-v2-pre
Problem
defaultNotFoundComponentused to be applied by lazily mutating the boundary route'soptions.notFoundComponentwhen anotFound()was handled (in load-matches). Route objects are module singletons shared across server requests, so once the server handled a single 404 for a route, every subsequent SSR of a valid URL on that route wrapped the match in aCatchNotFoundboundary.A freshly-hydrating client never runs that mutation, so it doesn't render the boundary — every
_hkunder the match shifts, hydration leaves the subtree unclaimed, and the result is visible but inert SSR DOM (no event handlers bound).Fix
Resolve
defaultNotFoundComponentat render time inMatch.tsxso the presence of theCatchNotFoundboundary — and therefore Solid's hydration keys — is deterministic on both server and client, regardless of whether the server previously served a 404.Tests
Added an e2e regression test in
e2e/solid-start/query-integration: