This is the frontend half of LiteStack β the backend half is LiteEnd-Go, and the whole stack comes up from the meta-repo (see its README). It also runs on its own β see "Standalone use" below.
A modern, scalable, and developer-friendly frontend boilerplate powered by Vite, React 19, GraphQL, and TypeScript. Built with the Feature-Sliced Design methodology and pre-configured OIDC Authentication.
LiteFront is a lightweight and performant frontend boilerplate designed for building fast, efficient, and well-structured web applications. It integrates a modern toolchain to provide an exceptional developer experience (DX) right out of the box.
- π Performance: Fast development server and optimized builds thanks to Vite.
- π Security: Enterprise-grade authentication via OpenID Connect (OIDC).
- π§© Scalability: Feature-Sliced Design ensures your project stays organized and maintainable as it grows.
- β Reliability: Type-safety with TypeScript, code quality enforced by Biome, and pre-commit checks with Lefthook.
- π§ͺ Test-Ready: Unit testing with Vitest and End-to-End testing with Playwright are pre-configured.
| Category | Technology |
|---|---|
| Core | Vite, React 19, TypeScript |
| SSR / Routing | TanStack Start + TanStack Router (SSR, type-safe) |
| Authentication | react-oidc-context (OAuth 2.0 / OIDC) |
| Data Fetching | GraphQL with URQL Client |
| State Management | Zustand |
| Styling | Tailwind CSS v4 + SCSS Modules |
| UI Components | daisyUI (for Tailwind CSS) |
| Internationalization | Paraglide JS (Type-safe) |
| Code Generation | GraphQL Code Generator |
| Linting/Formatting | Biome, Stylelint, Knip, Steiger |
| Git Hooks | Lefthook |
| Testing | Vitest (Unit), Playwright (E2E) |
| Component Dev | Ladle (Storybook alternative) |
| Performance / DX | React Scan (Performance debugging) |
| Deployment | Docker β Node SSR server (Nitro node-server) |
This boilerplate uses Feature-Sliced Design (FSD), a methodology for structuring frontend applications. It helps to keep the codebase clean, scalable, and easy to navigate by organizing code into layers (shared, entities, features, widgets, pages, app).
Three directories under src/ sit outside the layers on purpose β generated/ (codegen
output), graphql/ (its query documents) and routes/ (file-based routing); the seven
files in src/ itself are entry points.
- Secure Authentication: Fully integrated OIDC/OAuth 2.0 flow with PKCE, automatic token renewal, and
AuthGuardfor protected routes. - Protected Routes Example: Includes a demo
/accountroute that requires authentication and displays user profile data. - π Type-Safe I18n: Built-in internationalization powered by Paraglide JS, offering full type safety, tree-shaking, and small bundle size.
- Automated Type Generation:
npm run gengenerates TypeScript types from your GraphQL schema. - Runtime Configuration: The public
VITE_*values are read from the environment when the server boots (src/shared/config/env.ts), so one built image runs in any environment. A missing required variable stops the server at startup with the variable's name, instead of breaking a page later. - Server-Side Rendering: Public pages are server-rendered via TanStack Start (Nitro
node-server) for fast first paint and SEO; auth-only routes opt out withssr: false. - Production-Optimized: Multi-stage Dockerfile producing a small, self-contained Node SSR image (
.output). - Image Optimization: Automatic image optimization at build time with
vite-plugin-image-optimizer. - Dead Code & Dependency Analysis: Keeps the codebase clean with Knip by detecting unused files, exports, and dependencies.
- Architectural Linting: Strict FSD boundaries enforced by Steiger.
- Performance Debugging: Built-in React Scan for debugging performance and unexpected renders in development mode.
- PWA Ready: Pre-configured Vite PWA plugin for transforming the app into a Progressive Web App.
The application requires the following environment variables for the OIDC authentication to work correctly. Set them however you like β a .env file is one way, exported variables are another; the server reads them from its environment when it boots.
| Variable | Description | Example |
|---|---|---|
VITE_OIDC_AUTHORITY |
The URL of your OIDC provider (Logto, Auth0, Keycloak, etc.) | https://your-app.logto.app/oidc |
VITE_OIDC_CLIENT_ID |
The Client ID of your application registered in the provider | abc123xyz... |
VITE_OIDC_REDIRECT_URI |
The callback URL where the user is redirected after login | http://localhost:3000/callback |
VITE_OIDC_SCOPE |
The scopes to request | openid profile offline_access |
VITE_OIDC_API_RESOURCE |
API resource indicator. Sent on both the authorize and token requests so the access token is a JWT whose aud equals the backend's OIDC_AUDIENCE |
http://localhost:4000 |
VITE_GRAPHQL_API_URL |
URL of your GraphQL API | http://localhost:4000/graphql |
VITE_BASE_URL |
Base URL of the application (E2E base URL, and used to build OIDC redirect targets β an empty value breaks sign-out) | http://localhost:3000 |
VITE_MOCK_AUTH |
Build-time. Bypasses real OIDC entirely (dev/E2E only β never ship it enabled) | false |
VITE_APP_VERSION |
Version string surfaced in the UI and Sentry releases | build metadata |
PORT |
The port the application will run on | 3000 |
VITE_SENTRY_DSN |
Runtime. The DSN key for Sentry error tracking | https://xxx@yyy.ingest.sentry.io/zzz |
VITE_SENTRY_ORG |
Build-time. Sentry organization slug (source maps) | your-org |
VITE_SENTRY_PROJECT |
Build-time. Sentry project name (source maps) | your-project |
VITE_SENTRY_AUTH_TOKEN |
Build-time. Token for uploading source maps | sntrys_... |
The env vars only tell the app where the provider is β register the app in the Logto Console too:
- Create a
Single Page App(Applications β Create). PKCE-based, no client secret. Copy its App ID intoVITE_OIDC_CLIENT_ID. - Redirect URIs (app settings): sign-in
http://localhost:3000/callback(=VITE_OIDC_REDIRECT_URI), post sign-outhttp://localhost:3000. Add production URLs when you deploy. - Register an API Resource (Console β API Resources β Create). Set its API Identifier to
exactly
VITE_OIDC_API_RESOURCE(e.g.http://localhost:4000, no trailing slash), then enable the resource's Default API toggle. Without a resource-bound token Logto issues an opaque token the backend can't verify β401 Unauthorized.
Three values must match exactly:
VITE_OIDC_API_RESOURCE(frontend) ==OIDC_AUDIENCE(backend) == the API Identifier in Logto.
VITE_OIDC_AUTHORITYis the OIDC endpoint β the Logto base URL plus/oidc(e.g.https://auth.example.com/oidc). The frontend sends theresourceon both the authorize and token requests (seesrc/features/auth/api/oidc-client.ts); sending it only on authorize yields an opaque token.
This boilerplate uses a facade pattern for authentication located in src/features/auth. This architecture decouples the application from the specific OIDC library, allowing you to replace it with any other method (e.g., custom JWT/Session based auth) easily.
To replace OIDC with your own logic:
- Open
src/features/auth/index.ts. - Remove
react-oidc-contextexports. - Implement and export your own
AuthProvidercomponent anduseAuthhook from this file. - Update
src/app/bootstrap/AppProviders.tsx(the isomorphic auth + GraphQLWrap) to mount your provider and drop thegetOidcConfig()injection if your new provider doesn't need it.
npm run start:dev: Starts the development server with Hot Module Replacement.npm run build: Bundles the application for production.npm run test:prod: Runs the unit/component tests once (Vitest). End-to-end tests arenpm run test:e2e:prod;npm run test:allruns both.npm run check: Runs all code quality checks in parallel:tsc,biome(in write mode β it fixes rather than fails),stylelint,knip,steiger, and the component trio check. This is the gate β never substitutelint+ts:check.npm run verify:commit/verify:push: exactly what the git hooks run.npm run lint:fsd: Manually runs FSD layer boundary checks with Steiger.npm run storybook:serve: Starts the component playground (Ladle) for developing UI components.npm run storybook:build: Builds the static storybook for deployment.npm run gen: Generates TypeScript types for GraphQL operations.
Inside LiteStack, scripts/setup.sh at the meta root does all of this. On its own β
everything in Docker, nothing to install but Docker:
cp -n .env.example .env && docker compose up -dFrom source:
-
Install dependencies
npm install
-
Setup environment variables
cp .env.example .env
Important: Open
.envand fill in your OIDC provider details (VITE_OIDC_AUTHORITY,VITE_OIDC_CLIENT_ID, etc.) or the app will not be able to authenticate users. -
GraphQL types are already generated and committed in
src/generated/β runnpm run genonly after the backend schema changes. -
Run the development server
npm run start:dev
Your app should now be running on the port specified in your .env file (default: http://localhost:3000).
Run npm run gen after every change to the GraphQL API Schema or after modifying any *.graphql files in the src/graphql directory. This command is crucial for maintaining type safety between your frontend and backend.
This boilerplate includes a complete testing infrastructure for both unit and end-to-end testing.
- Unit/Component Tests: Written with Vitest and Testing Library for testing React components and Zustand stores.
- E2E Tests: Run on Playwright with pre-configured Mock Auth β allows stable test runs without requiring a real OIDC provider.
npm run test:prod# Run in headless mode
npm run test:e2e:prod
# Run with UI
npm run test:e2e:devnpm run test:covThis application uses Sentry for production error tracking and performance monitoring. The integration includes automatic source map uploading during the build process via @sentry/vite-plugin.
To enable Sentry, configure the following environment variables:
VITE_SENTRY_DSN=your-sentry-dsn
VITE_SENTRY_ORG=your-sentry-org
VITE_SENTRY_PROJECT=your-sentry-project
VITE_SENTRY_AUTH_TOKEN=your-auth-token # Required only at build time(Note: VITE_SENTRY_AUTH_TOKEN is a secret β set it in the build environment, never commit it.)
Outside LiteStack this repo stands alone. Inside it does not β frontend/ is a submodule pinned to a commit, so start from the meta-repo.
npx degit uxname/litefront my-app && cd my-app && npm install && cp .env.example .env && npm run start:devLiteFront is licensed under the MIT License.
Contributions are welcome! Please feel free to open an issue or submit a pull request with your changes.
