7e3808237e
- Dockerfile: three-stage (deps / build / runtime). deps stage runs pnpm fetch with BuildKit cache mount; build stage runs vite build to produce dist/; runtime stage is nginx:1.27-alpine serving the bundle. HEALTHCHECK via wget against localhost. - nginx.conf: gzip on text assets; /assets/ long-cache (hashed filenames immutable); /config.json no-cache (volume-mountable override in stage/prod); /index.html no-cache; SPA routing fallback via try_files ... /index.html. - .dockerignore: keeps the context small (node_modules, dist, env, .git, .gitea, .planning, *.md except README, .claude, .vscode). - .gitea/workflows/build.yml: matches trm/processor shape with format:check added between lint and test. Path filter excludes .planning and pure-markdown changes. Steps: checkout, Node 22, pnpm@latest-9, install --frozen-lockfile, typecheck, lint, format:check, test, buildx, registry login, build & push trm/spa:main, Portainer webhook. Deviations from spec: - Push :main tag only (not :main + per-commit SHA). Matches the other repos; SHA-pinning happens via *_TAG env vars in trm/deploy. SHA tagging is a cross-repo refactor for later. - Pin pnpm@latest-9 (matching existing repos), not pnpm@latest from the spec. Reproducibility win for CI. Smoke: typecheck/lint/format:check/build all green locally. Local docker build not run (Docker unavailable on this machine); CI is the gate. Required for first deploy (1.10 covers the rest): - REGISTRY_USERNAME / REGISTRY_PASSWORD / PORTAINER_WEBHOOK_URL secrets in the Gitea repo settings. - SPA service block in trm/deploy/compose.yaml.
40 lines
1.2 KiB
Nginx Configuration File
40 lines
1.2 KiB
Nginx Configuration File
server {
|
|
listen 80;
|
|
server_name _;
|
|
root /usr/share/nginx/html;
|
|
index index.html;
|
|
|
|
# Compression for text assets. Brotli is a follow-up if it becomes a concern.
|
|
gzip on;
|
|
gzip_types text/css application/javascript application/json image/svg+xml;
|
|
gzip_min_length 1024;
|
|
gzip_vary on;
|
|
|
|
# Hashed assets — long cache (Vite emits content-hashed filenames).
|
|
location /assets/ {
|
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# Runtime config — overridable in stage/prod via a Docker volume mount onto
|
|
# /usr/share/nginx/html/config.json. Never cached so deploy-time overrides
|
|
# take effect on the next page load.
|
|
location = /config.json {
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
expires off;
|
|
try_files $uri =404;
|
|
}
|
|
|
|
# index.html — never cache; the index references the hashed asset names.
|
|
location = /index.html {
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
expires off;
|
|
}
|
|
|
|
# SPA routing fallback — every unknown path falls through to index.html so
|
|
# the client-side router (TanStack Router) can resolve it.
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
}
|