refactor(solid-router): move off sharedConfig onto Solid 2.0 public hydration APIs (solid-js rc.13) - #8569
Conversation
….0.0-next.46
Bump solid-js and @solidjs/web to ^2.0.0-rc.13 across the monorepo,
@solidjs/vite-plugin to ^3.0.0-next.46 (its compiler range resolves to
rc.13, keeping the JSX compiler on the runtime's RC), the webpack
example's @solidjs/babel-plugin and the @rsbuild/plugin-solid compiler
overrides to 2.0.0-rc.13, and raise the Solid packages' solid-js /
@solidjs/web peer floors to 2.0.0-rc.13.
rc.13 replaced attribution.navigations() with
attribution.history('navigation'); observe-navigation.test.tsx follows.
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…olid 2.0 APIs Replace solid-js internals with the public hydration surface shipped in solid-js / @solidjs/web 2.0.0-rc.13 (solidjs/solid#3718): - useHydrated: sharedConfig.hydrating -> isHydrating() - serializeMatchTransfer: sharedConfig.context.serialize -> getHydrationWriter().write, gated on isHydratable() (the old context.noHydrate guard was dead in 2.0) - primeRouterFromRegistry: raw _$HY.r reads, the tsr: prefix scan and s/v unwrapping -> per-match takeHydrationValue() - tests / external-SSR repro: drop the sharedConfig reset and _$HY enumeration; the repro asserts entries server-side and consumption through takeHydrationValue Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
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: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Why
In the Solid 2.0 RC,
sharedConfig(and everything reachable fromsolid-js/internal) is internal runtime state: its shape changes between RCs without notice, and reads of the raw_$HYregistry depend on the wire format.@tanstack/solid-routerwas reading both for its native SSR match transfer and foruseHydrated. Solid now ships a small public hydration API for exactly these jobs, insolid-js/@solidjs/web2.0.0-rc.13 (solidjs/solid#3718):This PR bumps the Solid packages to rc.13 and moves the router onto that API. After it, no Solid package in this repo reads
sharedConfig, importssolid-js/internal, or touches_$HY.Survey
git grep -n -E "sharedConfig|solid-js/internal|_\$HY|noHydrate"across the Solid packages:solid-router/src/ClientOnly.tsxSolid.sharedConfig.hydratingisHydrating()solid-router/src/registryTransfer.ts(server)sharedConfig.context.serialize,context.noHydrateguardgetHydrationWriter()+isHydratable()solid-router/src/registryTransfer.ts(client)_$HY.rreads,tsr:prefix scan,delete,s/vunwrappingtakeHydrationValue()per matchsolid-router/tests/matches-hydration-boundary.test.tsxsharedConfig.hydrating = falseresetsolid-router/repro-external-ssr/entry-client.tsx_$HY.rfortsr:keystakeHydrationValue+ server-side assertionsolid-start/src/plugin/vite.ts_$HY.donegetRequestEvent/provideRequestEventwere already on the public@solidjs/webexports; nothing to change there.Changes
packages/solid-router/src/registryTransfer.tsserializeMatchTransfer):sharedConfig.context.serialize(key, v)→getHydrationWriter()?.write(key, v), gated onisHydratable(). The oldctx.noHydrateguard was dead code in 2.0 (the field no longer exists), so match transfer is now skipped under<NoHydration>, where it was previously written.primeRouterFromRegistry): the raw_$HY.rread, thetsr:-prefix pre-scan, the manualdelete, and thes/vsettled-promise unwrapping are replaced bytakeHydrationValue(MATCH_KEY_PREFIX + match.id)per matched route. Onlystatus: 'resolved'entries prime;pending/rejected/ missing fall through to the existing boot, as before.packages/solid-router/src/ClientOnly.tsxuseHydrated:globalHydrated && !sharedConfig.hydrating→globalHydrated && !isHydrating().Tests and repro
tests/matches-hydration-boundary.test.tsx: drop thesharedConfig.hydrating = falsereset.tests/observe-navigation.test.tsx: rc.13 replacedattribution.navigations()withattribution.history('navigation')(a Solid API change in this RC range, not part of the hydration work).repro-external-ssr/: the client no longer enumerates_$HY.r. The runner asserts that the server shell chunk carriestsr:entries, and the client asserts every committed match's entry was taken (takeHydrationValuereturnsundefined). The runner also copiesTextEncoder/TextDecoderinto jsdom, because rc.13's@solidjs/webserver-function protocol module creates its event-stream heartbeat at module scope and jsdom has no encoding globals.Dependency and peer-dependency changes
solid-js,@solidjs/web:^2.0.0-rc.9→^2.0.0-rc.13in every package, example, e2e app, and benchmark that declared them.@solidjs/vite-plugin:^3.0.0-next.44→^3.0.0-next.46. next.44 locked@solidjs/compilerat rc.9; next.46's range resolves to rc.13, keeping the JSX compiler on the runtime's RC.@solidjs/babel-plugin(webpack quickstart) and the@rsbuild/plugin-solid>@solidjs/{compiler,babel-plugin}overrides inpnpm-workspace.yaml:2.0.0-rc.9→2.0.0-rc.13.@tanstack/solid-router,solid-start,solid-start-client,solid-start-server:solid-js/@solidjs/web>=2.0.0-0 <3.0.0(start: web>=2.0.0-rc.6) →>=2.0.0-rc.13 <3.0.0@tanstack/solid-router-ssr-query:>=2.0.0-beta.17→>=2.0.0-rc.13@tanstack/solid-router-devtools:^2.0.0-rc.9→^2.0.0-rc.13@emnapientries dropped with the rc.9 compiler).No public exports of the TanStack packages change.
Behavior notes
<NoHydration>: settled match state is no longer serialized under<NoHydration>(see above).useHydratedinitial value:sharedConfig.hydratingstayedtrueafter the root hydration pass while streamed boundaries were still pending, so a component created client-side in that window started withhydrated() === false.isHydrating()istrueonly inside a claim window (the root pass, or a streamed boundary resuming), so such a component now startstrue. Components inside a resuming boundary still startfalse.GenericHydrate(solid-start-client) reads this at creation; the deferred-hydration e2e passes.tsr:key before runningmatchRoutes. There's intentionally no API to enumerate keys, so the boot now runs one purematchRoutespass on every client router construction (SPA and Start included) and falls through at the first missing key. That pass calls uservalidateSearch/loaderDeps/params.parseonce more on those boots.onHydrationEnd/_$HY.done/sharedConfig.donedependence;useHydratedflips on its first effect run, after the root pass.Validation (published solid-js / @solidjs/web / @solidjs/signals 2.0.0-rc.13)
A single copy of
solid-js,@solidjs/web, and@solidjs/signalsresolves from every Solid package.@tanstack/solid-router:tsc -p tsconfig.legacy.jsonclean; vitest (jsdom) 889 passed / 2 skipped; vitest--mode server7 passed; ESLint clean on the changed files;vite buildOK.repro-external-ssr(renderToStream → jsdom hydrate): PASS.tsr:entries were in the shell chunk, the router was primed at construction with 0 loader runs before and after hydrate, the server node was reused, there was no pending flash, deferred data streamed, and post-hydration navigation showed pending UI.solid-start-client(tsc + 8 tests),solid-start-server(tsc + vitest),solid-router-ssr-query(tsc + vitest),solid-router-devtools(tsc): all pass.e2e/solid-start/basic80 passed / 4 skipped;e2e/solid-start/deferred-hydration(Vite) 15 passed.history()rename).Not run locally: the rsbuild variants, and the full e2e matrix.
On behalf of @ryansolid.
— Claude via Cursor