A modern, server-side rendered movie catalog application built with React, Vite SSR, and Feature-Sliced Design architecture. Explore trending movies, discover new titles, and manage your personal watchlist.
Live DEMO: Ranflix Official DEMO Page
- Server-Side Rendering (SSR) with Vite
- Modern UI with smooth animations powered by Motion (Framer Motion)
- Movie Discovery - Browse trending movies and discover by genre
- Watchlist Management - Save and organize your favorite movies
- Fully Responsive - Optimized for mobile, tablet, and desktop
- Type-Safe - Built with TypeScript for reliability
- Comprehensive Testing - 80%+ test coverage with Vitest
- Accessible - Following WCAG guidelines
- Add a useOutsideClick hook to handle closing dropdowns, selectors, and upcoming modals consistently.
- Refactor the Movie Detail view by componentizing its sections (overview, metadata, similar titles, etc.) to enable reuse across other parts of the app.
- Implement a global ErrorBoundary to gracefully catch runtime errors and render a fallback UI.
- Add logging within the ErrorBoundary to capture and persist error details (message, stack trace, component state) for debugging and diagnostics.
- Fix scroll restoration when navigating between pages (preserve or reset position as needed).
- Automatically close the mobile navigation menu after navigating from detail views (e.g., Movie Detail → Watchlist).
- Persist the Watchlist state using APIs such as TMDB guest sessions.
- Implement dynamic metadata (SSR + client) via generateMeta() in routes to enhance SEO and link previews.
- Add accessibility improvements — focus trapping in modals, ARIA labels for buttons, and keyboard navigation for sliders.
- Optimize image loading in movie cards and hero banners with lazy loading and responsive srcset.
- Review and optimize bundle size by applying code splitting and efficient dependency management.
- React 19 - UI library
- Vite - Build tool with SSR support
- TypeScript - Type safety
- TanStack Query - Data fetching management
- Zustand - Client state management
- Axios - HTTP client
- React Router 7 - Routing
- Vitest - Unit & integration testing
- Testing Library - Component testing
- ESLint - Code linting
- Prettier - Code formatting
- Stylelint - CSS linting
- Husky - Git hooks
- Feature-Sliced Design (FSD) - Architectural methodology
Following Feature-Sliced Design principles:
rankflix/
├── src/
│ ├── app/ # Application layer
│ │ ├── layouts/ # Layout components
│ │ ├── providers/ # Global providers (Router, Query, Store)
│ │ └── styles/ # Global styles & variables
│ │
│ ├── pages/ # Pages layer
│ │ ├── home/ # Home page
│ │ ├── movie-detail/ # Movie detail page
│ │ ├── watchlist/ # Watchlist page
│ │ └── not-found/ # 404 page
│ │
│ ├── widgets/ # Widgets layer
│ │ ├── header/ # Header component
│ │ ├── navbar/ # Navigation bar
│ │ └── footer/ # Footer component
│ │
│ ├── features/ # Features layer
│ │ ├── discovery-movies/ # Movie discovery features
│ │ ├── movie-detail/ # Movie detail features
│ │ └── watchlist/ # Watchlist management
│ │
│ ├── entities/ # Entities layer
│ │ ├── movies/ # Movie entity (types, api, ui)
│ │ └── list/ # List entity
│ │
│ ├── shared/ # Shared layer
│ │ ├── api/ # API clients & types
│ │ ├── config/ # App configuration
│ │ ├── hooks/ # Reusable hooks
│ │ ├── lib/ # Utility functions
│ │ ├── routes/ # Route definitions
│ │ └── ui/ # Shared UI components
│ │
│ ├── tests/ # Test utilities
│ ├── entry-client.tsx # Client entry point
│ └── entry-server.tsx # SSR entry point
│
├── server/ # Express SSR server
│ ├── index.js # Development server
│ └── build.js # Production server builder
│
└── dist/ # Build output
├── client/ # Client-side bundle
├── server/ # SSR bundle
└── index.js # Production server
shared/- Reusable utilities, UI kit, and third-party lib configsentities/- Business entities (e.g., Movie, User)features/- User interactions and business featureswidgets/- Composite blocks and templatespages/- Application pagesapp/- App-wide settings, providers, and global styles
- Node.js >= 22.x
- npm >= 10.x
- TMDB API Key - Get one from The Movie Database
-
Clone the repository
git clone https://github.com/manugo-dev/rankflix.git cd rankflix -
Install dependencies
npm install
-
Set up environment variables
Create a
.envfile in the root directory:VITE_TMDB_API_KEY=your_tmdb_api_key_here VITE_TMDB_API_BASE_URL=https://api.themoviedb.org/3 VITE_TMDB_IMAGE_BASE_URL=https://media.themoviedb.org/t/p/
Start the development server with hot module replacement (HMR):
npm run devThe application will be available at http://localhost:5174
npm run dev:client # Start Vite dev server only (client-side)
npm run typecheck # Run TypeScript type checking
npm run lint # Run all linters (ESLint, Prettier, Stylelint)
npm run lint:fix # Auto-fix linting issues
npm run test # Run tests in watch mode
npm run test:ui # Run tests with Vitest UI
npm run test:coverage # Run tests with coverage reportBuild the application for production:
npm run buildThis will:
- Build the client bundle (
dist/client/) - Build the SSR bundle (
dist/server/) - Build the production server (
dist/index.js)
npm run build:client # Build client-side only
npm run build:ssr # Build SSR bundle only
npm run build:ssr-server # Build production server onlynpm startThe production server will run on http://localhost:3000
The project uses Vitest and Testing Library for comprehensive testing.
- Lines: 80%
- Functions: 80%
- Branches: 80%
- Statements: 80%
# Run tests in watch mode
npm test
# Run tests once (CI mode)
npm run test:ci
# Run tests with coverage
npm run test:coverage
# Run tests with UI
npm run test:uiTests are co-located with their source files:
src/
├── entities/
│ └── movies/
│ ├── ui/
│ │ ├── movie-card/
│ │ │ ├── movie-card.tsx
│ │ │ └── movie-card.test.tsx
# Check code quality
npm run lint
# Auto-fix issues
npm run lint:fix:eslint
npm run lint:fix:prettier
npm run lint:fix:stylelintPre-commit hooks (via Husky and lint-staged):
- Type checking
- Linting
- Formatting
- Running tests for changed files
Following Conventional Commits:
feat: add new feature
fix: bug fix
docs: documentation changes
style: code style changes
refactor: code refactoring
test: test changes
chore: build process or auxiliary tool changesThe application is deployed to Vercel using GitHub Actions.
Runs on every push to main and on pull requests:
- TypeCheck - Validate TypeScript types
- Prettier - Check code formatting
- ESLint - Lint JavaScript/TypeScript
- Stylelint - Lint CSS/SCSS
- Tests - Run test suite with coverage
- Build - Ensure production build succeeds
- Badge - Update coverage badge
Triggered on push to main after CI passes:
- CI Job - Runs full CI pipeline
- Deploy Job - Deploys to Vercel
- Installs Vercel CLI
- Pulls Vercel environment
- Builds project artifacts
- Deploys to production
Configure in GitHub repository settings:
VERCEL_TOKEN- Vercel deployment tokenGIST_TOKEN- GitHub token for badges (optional)
BADGES_GIST_URL- URL for coverage badges (optional)
# Install Vercel CLI
npm install -g vercel
# Deploy to preview
vercel
# Deploy to production
vercel --prod| Variable | Description | Example |
|---|---|---|
VITE_TMDB_API_KEY |
The Movie Database API key | your_api_key |
| Variable | Description | Default |
|---|---|---|
VITE_TMDB_API_BASE_URL |
TMDB API base URL | https://api.themoviedb.org/3 |
VITE_TMDB_IMAGE_BASE_URL |
TMDB image base URL | https://media.themoviedb.org/t/p/ |
- Follow Feature-Sliced Design principles
- Write tests for new features
- Maintain 80%+ coverage
- Use conventional commits
- Update documentation
- The Movie Database (TMDB) - Movie data API
- Feature-Sliced Design - Architecture methodology
- Vite - Build tool
Built with ❤️ using React, Vite, and Feature-Sliced Design