A clean, minimal client-rendered React 18 starter. Routing, data fetching, theming, GDPR cookie consent, and a production-ready Express preview server — wired up and ready to fork.
- Routing — TanStack Router with lazy-loaded routes, per-route
head()for SEO metadata - Data fetching — React Query v5 with Axios interceptors and reusable hooks
- Auth — OAuth 2.0 PKCE utilities (authorization, token refresh, sign-out)
- Theming — Dark/light toggle via CSS custom properties, persisted to localStorage
- Cookie consent —
vanilla-cookieconsentv3, GDPR-ready, keyboard shortcuts (A/N/P/S) - UI — React-Bootstrap (selective imports), lucide-react icons, navigation progress bar
- Build — Vite 5, Brotli + gzip compression, content-hashed assets
- Dev — ESLint, Prettier, Vitest, GitHub Actions CI
- Node.js ≥ 20
- npm ≥ 10
git clone https://github.com/spinellifabio/vite-react-starter-kit.git
cd vite-react-starter-kit
npm install
cp .env.example .env.local # fill in your values
npm run devSee .env.example for all available variables with descriptions.
Key variables:
| Variable | Description |
|---|---|
VITE_SITE_URL |
Canonical base URL (used for SEO and JSON-LD) |
VITE_SITE_NAME |
Site name for Open Graph and structured data |
VITE_OG_IMAGE |
Absolute URL to the 1200×630 OG share image |
VITE_API_BASE_URL |
API base URL for the Axios client (default: /api) |
VITE_OAUTH_* |
OAuth 2.0 PKCE settings (optional) |
npm run dev # Vite dev server with HMR
npm run build # Production build → dist/client/
npm run preview # Serve production build locally
npm run lint # ESLint
npm run test # Vitest (run once)
npm run test:ui # Vitest with browser UI├── .github/
│ └── workflows/ci.yml # Lint + test + build on push/PR
├── server/
│ ├── index.js # Express preview server (compression, caching)
│ └── dev-server.js # Vite middleware mode for local dev
├── src/
│ ├── components/
│ │ ├── layout/ # RootLayout, SiteHeader, SiteFooter, PageTransitionBar
│ │ └── ui/ # HeroSection, ContactCta, ThemeToggle
│ ├── lib/
│ │ ├── api/ # Axios client + React Query hooks
│ │ ├── oauth/ # OAuth 2.0 PKCE utilities
│ │ ├── i18n/ # Cookie consent translations
│ │ ├── cookieConsent.js # vanilla-cookieconsent config
│ │ ├── queryClient.js # React Query client factory
│ │ ├── seo.js # defaultSEO, resolveSeo(), buildJsonLd()
│ │ └── theme.jsx # ThemeProvider context
│ ├── pages/ # Home, About, PrivacyPolicy, NotFound
│ ├── styles/main.scss # Bootstrap (selective) + CSS custom properties
│ ├── test/ # Vitest unit tests
│ ├── entry-client.jsx # App bootstrap
│ └── router.jsx # TanStack Router tree
├── public/ # Static assets
├── .env.example # Environment variable reference
├── vite.config.js # Vite + Vitest config
└── eslint.config.js # ESLint flat config
The cookie banner is configured in src/lib/cookieConsent.js and uses a shell-themed UI.
Translations live in src/lib/i18n/consent.js — add more locales there.
Keyboard shortcuts (visible when the banner or preferences modal is open):
| Key | Action |
|---|---|
| A | Accept all |
| N | Necessary only |
| P | Open preferences |
| S | Save preferences |
npm run build
# Serve dist/client/ behind a reverse proxy (Nginx, Caddy, Cloudflare)
# or run the bundled Express server:
node server/index.jsCache strategy:
/assets/*— 1 year immutable (content-hashed filenames)/*— no-cache (ensures fresh HTML for every deploy)
See CONTRIBUTING.md.
MIT — see LICENSE.