React (Vite SPA) — Best Practices
AI Context & Token Optimization
- Feature-Sliced Design (FSD): Strictly group code by feature (e.g.,
features/auth/). This is critical for AI agents, as it keeps all related components, hooks, and APIs in a single localized directory, preventing context exhaustion from scanning global folders.
- Strict TypeScript: Always define
interface Props {} for components. Pure JS causes prop-drilling hallucinations.
- Zustand for State: Avoid Redux boilerplate. Use Zustand for minimal, easily readable global state.
Project Structure
src/
├── assets/ # Static assets
├── components/ # Shared, reusable UI components
│ ├── common/ # Buttons, Inputs, Modals
│ └── layout/ # Header, Sidebar
├── features/ # Feature-based modules
│ └── auth/ # Co-locate auth components, hooks, api
├── hooks/ # Global custom React hooks
├── pages/ # Route-level components
├── services/ # API clients and network calls
├── store/ # Global state (Zustand/Redux)
├── utils/ # Pure helper functions
├── App.tsx # Main entry and Router provider
└── main.tsx # Vite mount point
Naming Conventions
- Components:
PascalCase (e.g., UserProfile.tsx)
- Hooks:
camelCase starting with use (e.g., useTheme.ts)
- Files/Utils:
camelCase or kebab-case (e.g., formatDate.ts)
Architectural Patterns
- Feature-sliced Design: Group code by feature (
features/auth, features/dashboard) rather than by type, scaling better for large SPAs.
- State Management: Use
Zustand for global UI state. Use TanStack React Query for server state and data fetching.
- Strict typing: Use TypeScript interfaces for component props (
interface ButtonProps {}).
- Performance: Use
React.memo, useMemo, and useCallback only when profiling indicates a bottleneck, not preemptively.
Universal DateTime Governance
- API Boundary: Receive datetimes as epoch ms (number) or ISO-8601 UTC strings from the backend. Never parse timezone-naive date strings.
- Client Formatting: Use
Intl.DateTimeFormat with explicit timeZone option for user-facing display. Never rely on the browser's default timezone detection alone.
- Utilities: Use
dayjs with dayjs/plugin/utc for UTC normalization. Store all internal state as epoch ms. Only convert to localized strings at render time.
- State: Timestamps in Zustand stores must be epoch ms (number). Never store
Date objects in global state.
Testing Strategies
- Framework:
Vitest + React Testing Library.
- Approach: Render components, query by accessibility roles (
getByRole), and simulate user events using @testing-library/user-event.
1---2name: react-vite3description: React 18+ SPA architecture, hooks, and Vite configuration4---56# React (Vite SPA) — Best Practices78## AI Context & Token Optimization9101. **Feature-Sliced Design (FSD):** Strictly group code by feature (e.g., `features/auth/`). This is critical for AI agents, as it keeps all related components, hooks, and APIs in a single localized directory, preventing context exhaustion from scanning global folders.112. **Strict TypeScript:** Always define `interface Props {}` for components. Pure JS causes prop-drilling hallucinations.123. **Zustand for State:** Avoid Redux boilerplate. Use Zustand for minimal, easily readable global state.1314## Project Structure1516```17src/18├── assets/ # Static assets19├── components/ # Shared, reusable UI components20│ ├── common/ # Buttons, Inputs, Modals21│ └── layout/ # Header, Sidebar22├── features/ # Feature-based modules23│ └── auth/ # Co-locate auth components, hooks, api24├── hooks/ # Global custom React hooks25├── pages/ # Route-level components26├── services/ # API clients and network calls27├── store/ # Global state (Zustand/Redux)28├── utils/ # Pure helper functions29├── App.tsx # Main entry and Router provider30└── main.tsx # Vite mount point31```3233## Naming Conventions3435- **Components**: `PascalCase` (e.g., `UserProfile.tsx`)36- **Hooks**: `camelCase` starting with `use` (e.g., `useTheme.ts`)37- **Files/Utils**: `camelCase` or `kebab-case` (e.g., `formatDate.ts`)3839## Architectural Patterns4041- **Feature-sliced Design**: Group code by feature (`features/auth`, `features/dashboard`) rather than by type, scaling better for large SPAs.42- **State Management**: Use `Zustand` for global UI state. Use `TanStack React Query` for server state and data fetching.43- **Strict typing**: Use TypeScript interfaces for component props (`interface ButtonProps {}`).44- **Performance**: Use `React.memo`, `useMemo`, and `useCallback` only when profiling indicates a bottleneck, not preemptively.4546## Universal DateTime Governance4748- **API Boundary:** Receive datetimes as epoch ms (number) or ISO-8601 UTC strings from the backend. Never parse timezone-naive date strings.49- **Client Formatting:** Use `Intl.DateTimeFormat` with explicit `timeZone` option for user-facing display. Never rely on the browser's default timezone detection alone.50- **Utilities:** Use `dayjs` with `dayjs/plugin/utc` for UTC normalization. Store all internal state as epoch ms. Only convert to localized strings at render time.51- **State:** Timestamps in Zustand stores must be epoch ms (number). Never store `Date` objects in global state.5253## Testing Strategies5455- **Framework**: `Vitest` + `React Testing Library`.56- **Approach**: Render components, query by accessibility roles (`getByRole`), and simulate user events using `@testing-library/user-event`.