The card always displayed 1.0.0. VITE_APP_VERSION was never set: CI passes the release tag as a VERSION build arg, but the Dockerfile never declared it or forwarded it to the frontend build, so the hardcoded fallback always won. Declare the build arg and export it as VITE_APP_VERSION, and resolve the version in vite.config.ts for every other build: the env var, then the release tag via git describe, then package.json. The image version label was pinned at 1.0.0 for the same reason and now follows the arg too.
5.9 KiB
Frontend Documentation
Modern React 18 single-page application (SPA) built with TypeScript, Vite, and optimized libraries.
Tech Stack
- Framework: React 18.3 with TypeScript 5.4
- Build Tool: Vite 5.2
- Routing: React Router 6.22
- State Management:
- TanStack Query v5.28 for server state
- Zustand 4.5 for UI state
- Styling: Tailwind CSS 3.4
- UI Components: Shadcn UI (40+ components)
- Icons: Lucide React 0.358
- Form Handling: React Hook Form 7.71
- Game Emulation: Ruffle (Flash emulator)
Documentation Structure
Core Documentation
- architecture.md - Frontend architecture patterns
- views-routing.md - All views, routes, and route protection
- api-client.md - Axios client and API endpoints
- custom-hooks.md - 17+ custom hooks with examples
Components
- components/component-overview.md - Component organization
- components/layout-components.md - AppShell, Header, Sidebar
- components/game-components.md - GameCard, GameGrid, list components
- components/player-components.md - GamePlayer, RufflePlayer
- components/auth-components.md - LoginForm, RegisterForm, ProtectedRoute
- components/ui-components.md - Shadcn UI reference
State Management
- state-management/zustand-stores.md - useAuthStore, useThemeStore, useUIStore
- state-management/react-query.md - TanStack Query usage and caching
- state-management/url-state.md - URL-based filter state
Player Implementation
- player-implementation/ruffle-player.md - Flash game player
- player-implementation/html5-player.md - HTML5 game iframe player
Quick Start
Development Server
cd frontend
npm run dev
Starts at http://localhost:5173 with hot module replacement (HMR).
Building for Production
npm run build
Outputs to dist/ directory.
Preview Production Build
npm run preview
Type Checking
npm run typecheck
Key Features
Server State Management
All server data (games, playlists, user data) managed through TanStack Query:
- Automatic background refetching
- Optimistic updates
- Request deduplication
- Stale-while-revalidate patterns
UI State Management
Client-side UI state (sidebar, theme, auth) uses Zustand stores with localStorage persistence:
- Minimal boilerplate
- TypeScript-first
- DevTools support
- Middleware for persistence
Type Safety
Fully typed with TypeScript:
- Strict mode enabled
- No implicit any
- Comprehensive type definitions for API responses
- Type-safe form handling
Performance Optimizations
- Code splitting at route level
- Lazy loading for images and components
- Virtual scrolling for large game lists
- Memoization for expensive computations
- Request deduplication and caching
Accessibility
- ARIA labels on all interactive elements
- Keyboard navigation support
- Focus management
- Screen reader announcements
Environment Variables
The frontend does not require environment variables for local development. API calls are automatically proxied through Vite to the backend.
Optional (production builds):
VITE_APP_VERSION=1.0.38 # Displayed app version
vite.config.ts resolves the version at build time: VITE_APP_VERSION if set,
otherwise the release tag via git describe, otherwise package.json. Set it
explicitly only where neither is available — the Docker image carries no .git,
so CI passes the tag in through the VERSION build arg. Read it in components
from @/lib/version, never from import.meta.env directly.
Project Structure
frontend/
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── auth/ # Authentication components
│ │ ├── game/ # Game components
│ │ ├── layout/ # Layout components
│ │ ├── player/ # Game player components
│ │ └── ui/ # Shadcn UI components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # API client and utilities
│ ├── store/ # Zustand stores
│ ├── types/ # TypeScript types
│ ├── views/ # Page components
│ ├── App.tsx # Root component with routing
│ └── main.tsx # Entry point
├── public/ # Static assets
│ └── ruffle/ # Ruffle emulator files
└── index.html # HTML entry point
Vite Configuration
Dev server proxies both API and game content to backend:
server: {
proxy: {
'/api': 'http://localhost:3100',
'/game-proxy': 'http://localhost:3100',
'/game-zip': 'http://localhost:3100'
}
}
In production, Nginx proxies all requests to the backend container.
Common Commands
npm install # Install dependencies
npm run dev # Development server with HMR
npm run build # Production build
npm run preview # Preview production build
npm run typecheck # TypeScript type checking
npm run lint # ESLint code linting
Related Documentation
- Architecture Documentation - System architecture
- Backend Documentation - Backend API reference
- API Reference - Complete API documentation
- Development Workflow - Setup guide