Skip to content

Frontend Development

Guide to developing the Patrimoine frontend — a React 19 SPA built with Vite, Tailwind CSS v4, TanStack Query, and react-intl for i18n.


  • Node.js 24

Terminal window
cd frontend
npm ci

Terminal window
npm run dev

Runs on port 5173. The predev script generates src/generated/version.json before starting Vite.


Terminal window
npx oxlint

0 warnings and 0 errors must be maintained.


Terminal window
npx tsc -b --noEmit

TypeScript strict mode is enabled with noUnusedLocals and noUnusedParameters. See Code Style & Linting for details.


Terminal window
npx vitest run

Or in watch mode:

Terminal window
npx vitest

The suite contains about 5,000 tests across 372 files. See Testing for setup and helper details.


Terminal window
npm run build

This runs tsc -b && vite build. The prebuild script generates src/generated/version.json before the build.


Terminal window
npx size-limit

Limits (gzip):

Chunk Limit
Main bundle (app code + small deps) 350 KB
React vendor (react, react-dom, react-router) 200 KB
Recharts (lazy-loaded with ChartsPage) 450 KB

  1. Create src/pages/ThingPage.tsx.
  2. Add a lazy import in App.tsx wrapped in <Suspense>.
  3. Add a route with an errorElement fallback.
  4. Add the route to the routePrefetch map in src/routePrefetch.ts.
  5. Add the page to NAV_GROUPS (or EXTRA_PAGES) in src/components/layout/navItems.ts; the sidebar and the command palette read it, and paletteCommands.test.ts fails if a route has no command. Add the bottom-nav entry in BottomNav.tsx if it is a primary destination.

  1. Create src/hooks/useThing.ts.
  2. Follow the TanStack Query pattern used by existing hooks:
    • Define a queryKey array.
    • Use apiFetch for the API call.
    • Set an appropriate staleTime.
  3. Export the query keys so other components can invalidate the cache.

  1. Create the component in the appropriate src/components/ subdirectory.
  2. Use the cn() helper for className merging.
  3. Add a test file in a __tests__/ directory alongside the component.

Add translation keys to all five locale files:

  • src/locales/fr.json
  • src/locales/en.json
  • src/locales/es.json
  • src/locales/de.json
  • src/locales/it.json

Use <FormattedMessage id="key" /> in JSX, or useIntl().formatMessage() in logic.