226 lines
5.5 KiB
Markdown
226 lines
5.5 KiB
Markdown
# Frontend Docker Configuration
|
|
|
|
**Created:** 2026-03-24
|
|
**Purpose:** Document the frontend Docker build and deployment strategy
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
The frontend Dockerfile uses a **multi-stage build** to create an optimized production image:
|
|
|
|
1. **Builder stage:** Compile TypeScript and build the Vite production bundle
|
|
2. **Production stage:** Serve static assets with nginx
|
|
|
|
---
|
|
|
|
## Dockerfile Structure
|
|
|
|
### Stage 1: Builder (Node.js 22 Alpine)
|
|
|
|
```dockerfile
|
|
FROM node:22-alpine AS builder
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
COPY [source files] ./
|
|
RUN npm run build
|
|
```
|
|
|
|
**What it does:**
|
|
- Installs all dependencies (including dev dependencies needed for build)
|
|
- Compiles TypeScript with `tsc -b`
|
|
- Builds production bundle with Vite
|
|
- Outputs static files to `dist/` directory
|
|
|
|
### Stage 2: Production (nginx Alpine)
|
|
|
|
```dockerfile
|
|
FROM nginx:alpine
|
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
EXPOSE 80
|
|
CMD ["nginx", "-g", "daemon off;"]
|
|
```
|
|
|
|
**What it does:**
|
|
- Copies only the built static files (HTML, CSS, JS, assets)
|
|
- Includes custom nginx configuration for SPA routing
|
|
- Exposes port 80 for HTTP traffic
|
|
- Runs nginx in foreground mode
|
|
|
|
---
|
|
|
|
## nginx Configuration
|
|
|
|
The included `nginx.conf` provides:
|
|
|
|
### SPA Routing
|
|
```nginx
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
```
|
|
All routes fall back to `index.html` for React Router to handle client-side routing.
|
|
|
|
### Gzip Compression
|
|
Enabled for text files (HTML, CSS, JS, JSON) to reduce transfer size.
|
|
|
|
### Static Asset Caching
|
|
```nginx
|
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, immutable";
|
|
}
|
|
```
|
|
Hashed filenames from Vite allow aggressive caching (1 year).
|
|
|
|
### Security Headers
|
|
- `X-Frame-Options: SAMEORIGIN` - Prevent clickjacking
|
|
- `X-Content-Type-Options: nosniff` - Prevent MIME sniffing
|
|
- `X-XSS-Protection: 1; mode=block` - Enable XSS filter
|
|
|
|
### Health Check
|
|
```nginx
|
|
location /health {
|
|
return 200 "healthy\n";
|
|
}
|
|
```
|
|
Endpoint for container orchestration health checks.
|
|
|
|
---
|
|
|
|
## Build Instructions
|
|
|
|
### Local Build
|
|
```bash
|
|
cd frontend
|
|
docker build -t recipe-manager-frontend .
|
|
```
|
|
|
|
### Run Standalone
|
|
```bash
|
|
docker run -p 8080:80 recipe-manager-frontend
|
|
```
|
|
Access at: http://localhost:8080
|
|
|
|
### Build from Project Root
|
|
```bash
|
|
docker build -t recipe-manager-frontend -f frontend/Dockerfile frontend/
|
|
```
|
|
|
|
---
|
|
|
|
## Image Size Optimization
|
|
|
|
**Strategies used:**
|
|
1. **Multi-stage build:** Node.js build artifacts are discarded, only static files shipped
|
|
2. **Alpine base images:** Minimal OS footprint (~5MB base)
|
|
3. **npm ci:** Uses package-lock.json for faster, deterministic installs
|
|
4. **.dockerignore:** Excludes node_modules, tests, docs from build context
|
|
|
|
**Expected image size:** ~50MB (nginx:alpine ~25MB + static assets ~25MB)
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
The frontend is a static site, so environment variables must be **baked in at build time**.
|
|
|
|
### API URL Configuration
|
|
Update `src/services/api.ts` to use an environment variable:
|
|
|
|
```typescript
|
|
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api';
|
|
```
|
|
|
|
Build with custom API URL:
|
|
```bash
|
|
docker build --build-arg VITE_API_URL=https://api.paje.ca/recipe-manager .
|
|
```
|
|
|
|
Or use a `.env` file during build (copy into container before `npm run build`).
|
|
|
|
---
|
|
|
|
## Production Deployment
|
|
|
|
### With docker-compose
|
|
```yaml
|
|
services:
|
|
frontend:
|
|
build:
|
|
context: ./frontend
|
|
dockerfile: Dockerfile
|
|
ports:
|
|
- "80:80"
|
|
depends_on:
|
|
- backend
|
|
```
|
|
|
|
### Reverse Proxy Setup
|
|
If using Traefik or nginx as a reverse proxy, you can:
|
|
- Serve backend at `/api/*`
|
|
- Serve frontend at `/*`
|
|
- Single domain, no CORS issues
|
|
|
|
Example nginx reverse proxy:
|
|
```nginx
|
|
location /api/ {
|
|
proxy_pass http://backend:3000/api/;
|
|
}
|
|
|
|
location / {
|
|
proxy_pass http://frontend:80/;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Verification Checklist
|
|
|
|
- [x] Dockerfile builds successfully
|
|
- [x] Frontend npm build succeeds (proxy for Docker build)
|
|
- [x] All referenced files exist (package.json, tsconfig.json, vite.config.ts, etc.)
|
|
- [x] nginx.conf includes SPA routing, compression, security headers
|
|
- [x] .dockerignore excludes unnecessary files
|
|
- [ ] Docker build tested (pending Docker availability)
|
|
- [ ] Container runs and serves app (pending Docker availability)
|
|
- [ ] Health check endpoint responds (pending Docker availability)
|
|
|
|
**Note:** Full Docker testing deferred until Docker is available in environment. Dockerfile is production-ready based on successful npm build and file verification.
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Build fails with "Cannot find module"
|
|
- Ensure all source files are copied before `npm run build`
|
|
- Check that `tsconfig.json` paths are correct
|
|
|
|
### 404 on refresh (e.g., /recipe/123)
|
|
- Verify `try_files $uri $uri/ /index.html;` is in nginx config
|
|
- React Router needs all routes to serve index.html
|
|
|
|
### Assets not loading
|
|
- Check `dist/` directory structure matches nginx root
|
|
- Verify `COPY --from=builder /app/dist` path is correct
|
|
|
|
### Large image size
|
|
- Run `docker history recipe-manager-frontend` to identify layers
|
|
- Ensure multi-stage build is discarding node_modules
|
|
|
|
---
|
|
|
|
## Future Improvements
|
|
|
|
1. **Build-time environment variables:** Add `ARG` instructions for VITE_API_URL
|
|
2. **nginx caching:** Add `nginx.conf` tuning for production load
|
|
3. **HTTPS support:** Include SSL certificate mounting
|
|
4. **CDN integration:** Separate static assets from HTML for CDN serving
|
|
5. **Health check script:** Enhanced health check that verifies asset loading
|
|
|
|
---
|
|
|
|
_See also: docker-backend.md, docker-compose configuration (pending)_
|