Skip to content

Use server components for docs and the homepage - #258

Open
brookslybrand wants to merge 4 commits into
rsc-framework-minimalfrom
unstable-rsc-framework
Open

brookslybrand wants to merge 4 commits into
rsc-framework-minimalfrom
unstable-rsc-framework

Conversation

@brookslybrand

@brookslybrand brookslybrand commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #259, which is now on React Router 8.5.1. #259 handles the RSC migration and its workarounds. This PR moves the docs and homepage to server components.

Staging still runs an older 8.4 build and hasn't been redeployed for 8.5.1.

Try it on staging.

Server components

  • The doc page, docs layout, menu, brand page, and v6 index are now server components. The interactive bits (active TOC, copy buttons, link spinners, edit link, etc.) moved into small "use client" components.
  • The doc loader now sends only the title to the client instead of the whole doc. The rendered article is built once in the loader and reused by the route, so it isn't serialized into the Flight payload twice.

Homepage stats

  • Stats are now a server component, and the <Suspense> boundary is created in the loader. If the boundary lived in the route component instead, the whole RSC payload would wait on stats.
  • While loading, stats show a dashed placeholder (--,---,---) sized to the last known numbers, so the layout doesn't jump.

Search

  • The Algolia modal is now loaded with React.lazy when search is opened, instead of up front.
  • Importing anything from @docsearch/react pulls in the modal, so the search button and keyboard shortcut hook are now our own code. The button keeps the original icon and markup.

Color scheme

  • The theme toggle is a server function. With JavaScript, the server function stores the new value in root middleware's AsyncLocalStorage slot. The middleware then sets the cookie and loaders reload in place, which keeps the scroll position. Server function redirects can't pass preventScrollReset.
  • Without JavaScript, the form posts to the current page and the server function does throw replace(...) back to it. React Router 8.5.1 fixed duplicate headers on thrown server function redirects (RSC: throwing a redirect from a server function sends its headers twice react-router#15665), so this now uses the standard throw form.

Tests

  • Added tests for the new client components, the keyboard hook, lazy search, stats, and the doc and splash loaders. Cleaned up a few existing tests along the way.

I clicked through navigation, active links, copy buttons, theme switching, and search on staging, and checked HTML, Flight, and Markdown responses.

One caveat: RSC adds its own client runtime, so this isn't automatically less JS overall. Most of the initial-load savings come from lazy-loading search.

Validation on 8.5.1: build, typecheck, lint, and all 100 tests pass. Production-build smoke checks pass for HTML, bot HTML (stats render server-side, with the placeholder only in the Flight payload), Markdown, Flight, HEAD, and 404s. Client-side navigation, the server-function theme toggle (with and without JavaScript, single Set-Cookie), and hydration show no browser errors.

Generated by an AI agent on behalf of Brooks Lybrand. Model: Claude Opus 5.5; reasoning: unknown.

@brookslybrand
brookslybrand force-pushed the unstable-rsc-framework branch from 0fb574c to 29754bd Compare October 8, 2026 14:01
@brookslybrand brookslybrand changed the title Migrate to unstable RSC Framework Mode Adopt server components and polish search and stats Oct 8, 2026
@brookslybrand
brookslybrand changed the base branch from main to rsc-framework-minimal October 8, 2026 14:02
@brookslybrand
brookslybrand added this pull request to stack #260 October 8, 2026 14:07
@brookslybrand brookslybrand changed the title Adopt server components and polish search and stats Use server components for docs and the homepage Oct 8, 2026
@brookslybrand
brookslybrand force-pushed the unstable-rsc-framework branch from 29754bd to 31c8927 Compare October 8, 2026 14:55
@brookslybrand
brookslybrand force-pushed the unstable-rsc-framework branch from 31c8927 to 7cced18 Compare October 8, 2026 17:02
@brookslybrand
brookslybrand force-pushed the unstable-rsc-framework branch from 7cced18 to 2fba914 Compare October 19, 2026 18:31
@brookslybrand
brookslybrand force-pushed the unstable-rsc-framework branch from 2fba914 to 7057de5 Compare October 20, 2026 20:39
Replaces the /color-scheme route action with a "use server" function to
exercise server functions in RSC Framework Mode. It works without
JavaScript through React's progressive enhancement, and the theme still
switches instantly on submit.

The server function sets the cookie by registering a replace() redirect
back to the current page. React Router doesn't let server function
redirects keep the scroll position, so switching themes now scrolls to
the top.
Instead of redirecting back to the page to set the cookie, the server
function records the new color scheme for the request. Root middleware
sets the cookie on the response, and the root loader returns the new
value when loaders reload after the server function, so there's no
navigation and the scroll position is kept.

Without JavaScript, the server function still redirects so a refresh
doesn't resubmit the form.
React Router 8.5.1 no longer duplicates headers when a server function
throws a redirect (remix-run/react-router#15665), so use the standard
throw form.
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.

1 participant