3.3 KiB
${REPO_NAME}
Frontend service generated from nholtware/service-template-react: a Vite +
React 19 + React Router (data mode) SPA, served as static files by
unprivileged nginx.
Develop
npm install
npm run dev # http://localhost:5173, /api proxied to API_PROXY_TARGET (default http://localhost:3000)
npm test
npm run lint
npm run format
Runtime config
/config.js sets window.__APP_CONFIG__. In the container,
docker-entrypoint.d/10-config.sh writes it at start from env vars, so one
image runs in every environment. Read values through getConfig() in
src/lib/config.ts.
| Env var | Default | Meaning |
|---|---|---|
API_BASE_URL |
/api |
Backend base URL; /api is the same-host route |
APP_NAME |
app |
Display name |
UNLEASH_URL |
(empty) | Unleash base URL for the browser; empty = flags off |
UNLEASH_FRONTEND_TOKEN |
(empty) | Unleash frontend token (public by design) |
Everything in config.js is public. Never put secrets there.
Feature flags
Flags come from Unleash (UI: https://unleash.lab.holtlabs.xyz, environment development)
through its Frontend API, using the official @unleash/proxy-client-react SDK.
src/lib/flags.tsx wraps it: FlagsProvider is mounted once in main.tsx;
components call the wrappers, never the SDK directly:
import { useFlag, useVariant } from "../lib/flags";
const showBanner = useFlag("hello-banner");
- In the cluster the deployment sets
UNLEASH_URL=https://unleash.lab.holtlabs.xyzandUNLEASH_FRONTEND_TOKENfrom Secretunleash-client-token(keyfrontendToken). - The SDK fetches on load and refreshes every 15 s; components re-render on change. A reload always picks up the current state.
- With
UNLEASH_URLunset (localnpm run dev, tests) every flag readsfalse, nothing is fetched. - Tests:
vi.mock("@unleash/proxy-client-react")and controluseFlag(seesrc/app.test.tsx). hello-banneron the home page is the platform demo flag; delete it when you don't need it.
Container
GIT_SHAbuild arg is baked in asimport.meta.env.VITE_GIT_SHA.- nginx listens on 8080:
/healthzreturns 200, unknown paths fall back toindex.html,/assets/*are cached as immutable, andindex.htmlandconfig.jsare not cached. - Access log: one JSON line per request in the platform logging contract
(
level,time,service=APP_NAME,version=GIT_SHA,req.id(echoesX-Request-Id),req.method,req.url,res.statusCode,responseTimein ms,msg: "request completed"), the same shape as the backend template. In Kibana (https://kibana.lab.holtlabs.xyz, data viewkube-*):service:"${REPO_NAME}" and res.statusCode >= 400./healthzisn't logged. nginx's own startup/error lines stay plain text (fieldlog).
Deploy
Push to main: Forgejo CI runs lint/test/format, builds and pushes
git.holtlabs.xyz/nholtware/${REPO_NAME}:<sha>, and bumps the tag in the
gitops repo. ArgoCD then syncs it. Manifests come from gitops
templates/frontend/. The repo needs Actions secrets REGISTRY_USER,
REGISTRY_TOKEN, and GITOPS_TOKEN.