feat: keep fs-route params live for Client Components and expose route objects - #176
Merged
Conversation
…e objects Under file-system routing, all route components were baked into the RSC payload as pre-rendered elements, so dynamic params were frozen at the values of the initially-loaded page: soft client-side navigation between pages of the same dynamic route (e.g. /ja -> /en under [lang]) kept showing the old params everywhere, with no supported way to read the live ones. Two changes, per the discussion in #174: - Pass a Client Component page/layout to FUNSTACK Router as a component type instead of a pre-rendered element. Client references serialize through the RSC boundary, so the router renders them in the browser with the params of the current match; their `params` prop now stays live across soft navigation (along with the router's other route component props). - Assign a stable id to every generated route definition and pass Server Component pages/layouts a `route` prop: an opaque route object that can be forwarded to Client Components and given to the router's typed hooks (`useRouteParams(route)`) to read the live params of the URL currently shown. New types `FsRouteObject` and `FsRouteComponentProps` are exported from `@funstack/static/fs-routes`. A Server Component page's own rendered output still reflects its build-time params after soft navigation: static hosting serves one pre-rendered payload per page and nothing can re-run a Server Component in the browser. That remaining half of #174 needs on-navigation payload fetching and stays open. Refs #174 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMwvxdFVc7J44PszMubjsv
uhyo
commented
Aug 27, 2026
…ects Address review feedback on #176: - Update @funstack/router to ^1.4.0 (dev/peer/fixture/docs deps). The router now passes component-typed routes its route definition as a `route` prop, so Client Component pages and layouts receive a route object from the router itself and the fs-routes `route` prop is uniform across Server and Client Components. The Client Component fixture page and e2e now cover useRouteParams(route) with the router-provided prop. - Retype FsRouteObject on the router's new RouteHandle (the declared type of the `route` prop) instead of PartialRouteDefinition, and update FsRouteComponentProps docs for the uniform behavior. - Move isClientReference into a shared util module (src/util/clientReference.ts). - Docs: present the Server Component staleness as a temporary limitation being worked on (#174), and document that Client Components receive `route` from FUNSTACK Router v1.4+. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CMwvxdFVc7J44PszMubjsv
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
Addresses the client-component half of #174 (kept open for the remaining Server Component half).
Under file-system routing, every route component was baked into the RSC payload as a pre-rendered element, so dynamic params were frozen at the values of the initially-loaded page: soft client-side navigation between pages of the same dynamic route (e.g.
/ja→/enunder[lang]) kept showing the old params everywhere, with no supported way to read the live ones.Two changes:
"use client"page or layout is now passed to FUNSTACK Router as a component type instead of a pre-rendered element. Client references serialize through the RSC boundary, so the router renders them in the browser with the params of the current match — theirparamsprop stays live across soft navigation (along with the router's other route component props). No user code changes needed.routeprop: an opaque route object that can be forwarded to Client Components and given to the router's typed hooks (useRouteParams(route)) to read the live params of the URL currently shown. New typesFsRouteObject<Params>andFsRouteComponentProps<Params>are exported from@funstack/static/fs-routes.A Server Component page's own rendered output still reflects its build-time params after soft navigation: static hosting serves one pre-rendered payload per page and nothing can re-run a Server Component in the browser. That half of #174 needs on-navigation payload fetching and stays open.
Changes
fs-routes/runtime.tsx: pass client references as component types; assign per-node ids; bake{ params, route }into Server Component elements.fs-routes/types.ts/index.ts: newFsRouteObjectandFsRouteComponentPropstypes;FsRouteModule.defaultdocuments the new prop shape.fs-routes/tree.ts: export the existingisClientReferencehelper.routeprop, and the make-it-a-Client-Component escape hatch.Tests
params/routeprops on Server Component elements, id uniqueness, id portability across generated pages.[lang]client layout, Server Component page with auseRouteParamsclient child, Client Component page via the re-export pattern)./ja→/ensoft navigation, the client layout's params and the route-object read both showenwhile the Server Component page's baked output staysja; direct loads render correct params; no page errors during navigation.Full validation: unit tests, prod e2e suite (36/36), dev fs-routing e2e (8/8), typecheck, lint, and format all green.
🤖 Generated with Claude Code
https://claude.ai/code/session_01CMwvxdFVc7J44PszMubjsv
Generated by Claude Code