Skip to content

Latest commit

 

History

History
160 lines (112 loc) · 7.13 KB

File metadata and controls

160 lines (112 loc) · 7.13 KB

React Router Development Guide

Commands

  • Build: pnpm build (all packages) or pnpm run --filter <package> build (single package)
  • Test (Jest): pnpm test (all packages), pnpm test packages/<package>/ (single package), pnpm test packages/react-router/__tests__/router/fetchers-test.ts (single file), or pnpm test -- -t "action fetch" (tests matching name)
  • Integration tests (Playwright): pnpm test:integration --project chromium (build + test all), pnpm test:integration:run --project chromium (test only, all), pnpm test:integration:run --project chromium integration/middleware-test.ts (single file), or pnpm test:integration:run --project chromium -g "middleware" (tests matching name)
  • Typecheck: pnpm run typecheck
  • Lint: pnpm run lint
  • Docs generation: pnpm run docs (regenerates API docs from JSDoc)
  • Type generation: pnpm run typegen (Framework Mode only)
  • Clean: pnpm run clean (git clean -fdX)

Modes

Five distinct modes: Declarative, Data, Framework, RSC Data (unstable), RSC Framework (unstable). Always identify which mode(s) a feature applies to.

  1. Declarative: <BrowserRouter>, <Routes>, <Route>
  2. Data: createBrowserRouter() with loader/action, <RouterProvider>
  3. Framework: Vite plugin + routes.ts + Route Module API (route exports like loader, action, default) + type generation + SSR/SPA
  4. RSC Data (unstable): RSC runtime APIs, manual bundler setup, runtime route config
  5. RSC Framework (unstable): Framework Mode with unstable_reactRouterRSC Vite plugin

RSC mode differences:

  • RSC Framework: unstable_reactRouterRSC plugin, @vitejs/plugin-rsc, different entry points/format
  • RSC Data: Manual bundler, runtime route config typically in src/routes.ts, unstable_RSCRouteConfig, different runtime APIs, setupRscTest in integration/rsc/

Architecture

  • Monorepo: pnpm workspace, packages in packages/
  • Key packages:
    • react-router: Core (all modes) - lib/components.tsx, lib/hooks.tsx, lib/router/, lib/dom/, lib/rsc/
    • @react-router/dev: Framework tooling - vite/plugin.ts (Framework), vite/rsc/plugin.ts (RSC Framework), typegen/
    • react-router-dom: Re-exports react-router (v6→v7 compat)
    • @react-router/node, @react-router/cloudflare, @react-router/express: Server adapters
    • @react-router/serve: Minimal server for Framework Mode
    • @react-router/fs-routes: File-system routing (flatRoutes())

Testing

Unit Tests (packages/react-router/__tests__/)

Use Jest for pure routing logic, pure server runtime behavior, router state, React component behavior. No build required.

pnpm test                                                          # All packages
pnpm test packages/react-router/                                   # Single package
pnpm test packages/react-router/__tests__/router/fetchers-test.ts  # Single file
pnpm test -- -t "action fetch"                                     # Tests matching name

Integration Tests (integration/)

Use Playwright for Vite plugin, build pipeline, SSR/hydration, RSC, type generation.

pnpm test:integration --project chromium                                     # Build + test all
pnpm test:integration:run --project chromium                                 # Test only, all
pnpm test:integration:run --project chromium integration/middleware-test.ts  # Single file
pnpm test:integration:run --project chromium -g "middleware"                 # Tests matching name

Project: Always use chromium for integration tests, unless explicitly stated otherwise.

Rebuild when: First run, after changing packages/ (not needed for test-only changes)

Organization: Use createFixture()createAppFixture()PlaywrightFixture. Templates available: vite-6-template/, rsc-vite-framework/, etc. Test all applicable modes (iterate over template array when behavior should work across modes). Test both states when introducing future flags (one test with flag on, one with flag off).

RSC testing:

  • RSC Framework: Use createFixture with rsc-vite-framework/ template
  • RSC Data: Use setupRscTest in integration/rsc/

Test shared behavior across multiple templates (e.g., ["vite-5-template", "rsc-vite-framework"]). Test RSC-specific features against RSC template.

routes.ts

Framework Mode uses routes.ts in app/. Most tests use flatRoutes() for file-system routing:

// app/routes.ts
import { type RouteConfig } from "@react-router/dev/routes";
import { flatRoutes } from "@react-router/fs-routes";

export default flatRoutes() satisfies RouteConfig;

File-system conventions (app/routes/):

  • _index.tsx/ (index route)
  • about.tsx/about
  • blog.$slug.tsx/blog/:slug (URL param)
  • settings.profile.tsx/settings/profile (. creates nesting)
  • _layout.tsx → pathless layout route

Manual config alternative:

import { index, route, layout } from "@react-router/dev/routes";
export default [
  index("./home.tsx"),
  route("about", "./about.tsx"),
  layout("./auth-layout.tsx", [route("login", "./login.tsx")]),
];

Documentation

Don't edit generated files: docs/api/ (from JSDoc), .react-router/types/ (from typegen)

Mode indicators: Every doc needs [MODES: framework, data, declarative]

API docs: Edit JSDoc in packages/react-router/lib/, run pnpm docs

Unstable features: Prefix unstable_, add unstable: true to frontmatter, include warning block

Future Flags

  • Future flags (vX_*): Stable breaking changes for next major
  • Unstable flags (unstable_*): Experimental, may change

Test both states (on/off) for future flags. Don't break existing behavior without a flag.

Changesets

When making changes that affect users, create a changeset at .changeset/<unique-meaningful-name>.md. If iterating on a change that hasn't shipped yet, update the existing changeset file instead of creating a new one.

Format:

---
"react-router": patch
"@react-router/dev": minor
---

Brief description of the change

- Additional details if needed

Branching

  • main: Latest stable release
  • dev: Active development (branch from here for code changes)
  • v6: v6.x maintenance
  • Branch from main for docs-only changes

Key Files

Purpose Location
Router packages/react-router/lib/router/router.ts
React API packages/react-router/lib/components.tsx, lib/hooks.tsx
Vite plugin packages/react-router-dev/vite/plugin.ts
RSC Vite plugin packages/react-router-dev/vite/rsc/plugin.ts
Type generation packages/react-router-dev/typegen/
Unit tests packages/react-router/__tests__/
Integration tests integration/
Decision docs decisions/