📝 priettier check
All checks were successful
PR Checks / lint-and-build (pull_request) Successful in 18s

This commit is contained in:
RJ
2025-12-04 15:57:39 +02:00
parent b68325123b
commit 101624c4d5
32 changed files with 185 additions and 172 deletions

View File

@@ -5,6 +5,7 @@
This guide documents the configuration for build-time environment variables in the Next.js CI/CD pipeline.
**Problem Solved:** Next.js 16 requires `NEXT_PUBLIC_*` variables available during `npm run build` for:
- SEO metadata (`metadataBase`)
- Sitemap generation
- OpenGraph URLs
@@ -19,6 +20,7 @@ This guide documents the configuration for build-time environment variables in t
### 1. `.gitea/workflows/main.yml`
**Changes:**
- Added step to create `.env` from Gitea secrets (after checkout)
- Added cleanup step to remove `.env` after Docker push
@@ -34,7 +36,7 @@ This guide documents the configuration for build-time environment variables in t
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
EOF
echo "✅ .env file created successfully"
echo "Preview (secrets masked):"
cat .env | sed 's/=.*/=***MASKED***/g'
@@ -44,7 +46,7 @@ This guide documents the configuration for build-time environment variables in t
- name: 🚀 Push Docker image to registry
run: |
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
# Clean up sensitive files
rm -f .env
echo "✅ Cleaned up .env file"
@@ -55,6 +57,7 @@ This guide documents the configuration for build-time environment variables in t
### 2. `Dockerfile.nextjs`
**Changes:**
- Added `COPY .env* ./` in builder stage (after copying node_modules, before copying source code)
**Added Section:**
@@ -73,6 +76,7 @@ COPY .env* ./
### 3. `.dockerignore`
**Changes:**
- Modified to allow `.env` file (created by CI/CD) while excluding other `.env*` files
**Updated Section:**
@@ -85,6 +89,7 @@ COPY .env* ./
```
**Explanation:**
- `.env*` excludes all environment files
- `!.env` creates exception for main `.env` (from CI/CD)
- `.env.local`, `.env.development`, `.env.production.local` remain excluded
@@ -99,11 +104,12 @@ Navigate to: **Repository Settings → Secrets**
Add the following secret:
| Secret Name | Value | Type | Description |
|------------|-------|------|-------------|
| Secret Name | Value | Type | Description |
| ---------------------- | ------------------------ | ------------------ | ------------------- |
| `NEXT_PUBLIC_SITE_URL` | `https://yourdomain.com` | Secret or Variable | Production site URL |
**Notes:**
- Can be configured as **Secret** (masked in logs) or **Variable** (visible in logs)
- Recommended: Use **Variable** since it's a public URL
- For sensitive values (API keys), always use **Secret**
@@ -113,12 +119,14 @@ Add the following secret:
To add more build-time variables:
1. **Add to Gitea Secrets/Variables:**
```
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
NEXT_PUBLIC_API_URL=https://api.example.com
```
2. **Update workflow `.env` creation step:**
```yaml
cat > .env << EOF
NEXT_PUBLIC_SITE_URL=${{ secrets.NEXT_PUBLIC_SITE_URL }}
@@ -138,6 +146,7 @@ To add more build-time variables:
### Local Testing
1. **Create test `.env` file:**
```bash
cat > .env << EOF
NEXT_PUBLIC_SITE_URL=http://localhost:3030
@@ -147,24 +156,27 @@ To add more build-time variables:
```
2. **Build Docker image:**
```bash
docker build -t mypage:test -f Dockerfile.nextjs .
```
3. **Verify variable is embedded (should show "NOT FOUND" - correct behavior):**
```bash
docker run --rm mypage:test node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL || 'NOT FOUND')"
```
**Expected Output:** `NOT FOUND`
**Why?** `NEXT_PUBLIC_*` variables are embedded in JavaScript bundle during build, NOT available as runtime environment variables.
4. **Test application starts:**
```bash
docker run --rm -p 3030:3030 mypage:test
```
Visit `http://localhost:3030` to verify.
5. **Cleanup:**
@@ -214,10 +226,10 @@ To add more build-time variables:
### 🔒 Sensitive Data Guidelines
| Type | Use For | Access |
|------|---------|--------|
| `NEXT_PUBLIC_*` | Client-side config (URLs, feature flags) | Public (embedded in JS bundle) |
| `SECRET_*` | Server-side secrets (API keys, DB passwords) | Private (runtime only) |
| Type | Use For | Access |
| --------------- | -------------------------------------------- | ------------------------------ |
| `NEXT_PUBLIC_*` | Client-side config (URLs, feature flags) | Public (embedded in JS bundle) |
| `SECRET_*` | Server-side secrets (API keys, DB passwords) | Private (runtime only) |
---
@@ -226,10 +238,12 @@ To add more build-time variables:
### Issue: Variables not available during build
**Symptoms:**
- Next.js build errors about missing `NEXT_PUBLIC_SITE_URL`
- Metadata/sitemap generation fails
**Solution:**
- Verify `NEXT_PUBLIC_SITE_URL` secret exists in Gitea
- Check workflow logs for `.env` creation step
- Ensure `.env` file is created BEFORE Docker build
@@ -237,9 +251,11 @@ To add more build-time variables:
### Issue: Variables not working in application
**Symptoms:**
- URLs show as `undefined` or `null` in production
**Diagnosis:**
```bash
# Check if variable is in bundle (should work):
curl https://yourdomain.com | grep -o 'NEXT_PUBLIC_SITE_URL'
@@ -249,6 +265,7 @@ docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"
```
**Solution:**
- Verify `.env` was copied during Docker build
- Check Dockerfile logs for `COPY .env* ./` step
- Rebuild with `--no-cache` if needed
@@ -256,9 +273,11 @@ docker exec mypage-prod node -e "console.log(process.env.NEXT_PUBLIC_SITE_URL)"
### Issue: `.env` file not found during Docker build
**Symptoms:**
- Docker build warning: `COPY .env* ./` - no files matched
**Solution:**
- Check `.dockerignore` allows `.env` file
- Verify workflow creates `.env` BEFORE Docker build
- Check file exists: `ls -la .env` in workflow
@@ -289,6 +308,7 @@ After deploying changes:
## Support
For issues or questions:
1. Check workflow logs in Gitea Actions
2. Review Docker build logs
3. Verify Gitea secrets configuration

View File

@@ -1,4 +1,5 @@
# Production Optimizations Report
Date: 2025-11-24
Branch: feat/production-improvements
@@ -7,6 +8,7 @@ Branch: feat/production-improvements
Successfully implemented 7 categories of production optimizations for Next.js 16 blog application.
### Build Status: SUCCESS
- Build Time: ~3.9s compilation + ~1.5s static generation
- Static Pages Generated: 19 pages
- Bundle Size: 1.2MB (static assets)
@@ -17,10 +19,12 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 1. Bundle Size Optimization - Remove Unused Dependencies
### Actions Taken:
- Removed `react-syntax-highlighter` (11 packages eliminated)
- Removed `@types/react-syntax-highlighter`
### Impact:
- **11 packages removed** from dependency tree
- Cleaner bundle, faster npm installs
- All remaining dependencies verified as actively used
@@ -30,11 +34,13 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 2. Lazy Loading for Heavy Components
### Status:
- Attempted to implement dynamic imports for CodeBlock component
- Tool limitations prevented full implementation
- Benefit would be minimal (CodeBlock already client-side rendered)
### Recommendation:
- Consider manual lazy loading in future if CodeBlock becomes heavier
- Current implementation is already performant
@@ -45,16 +51,19 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Security Enhancements Applied:
**Dockerfile.nextjs:**
- Remove SUID/SGID binaries (prevent privilege escalation)
- Remove apk package manager after dependencies installed
- Create proper permissions for /tmp, /.next/cache, /app/logs directories
**docker-compose.prod.yml:**
- Added `security_opt: no-new-privileges:true`
- Added commented read-only filesystem option (optional hardening)
- Documented tmpfs mounts for extra security
### Security Posture:
- Minimal attack surface in production container
- Non-root user execution enforced
- Package manager unavailable at runtime
@@ -66,22 +75,26 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Files Created:
**app/sitemap.ts:**
- Dynamic sitemap generation from markdown posts
- Static pages included (/, /blog, /about)
- Posts include lastModified date from frontmatter
- Priority and changeFrequency configured
**app/robots.ts:**
- Allows all search engines
- Disallows /api/, /_next/, /admin/
- Disallows /api/, /\_next/, /admin/
- References sitemap.xml
**app/feed.xml/route.ts:**
- RSS 2.0 feed for latest 20 posts
- Includes title, description, author, pubDate
- Proper content-type and cache headers
### SEO Impact:
- Search engines can discover all content via sitemap
- RSS feed for blog subscribers
- Proper robots.txt prevents indexing of internal routes
@@ -93,16 +106,19 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Configuration Updates:
**Sharp:**
- Already installed (production-grade image optimizer)
- Faster than default Next.js image optimizer
**next.config.js - Image Settings:**
- Cache optimized images for 30 days (`minimumCacheTTL`)
- Support AVIF and WebP formats
- SVG rendering enabled with security CSP
- Responsive image sizes configured (640px to 3840px)
### Performance Impact:
- Faster image processing during builds
- Smaller image file sizes (AVIF/WebP)
- Better Core Web Vitals (LCP, CLS)
@@ -113,21 +129,25 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
### Cache Headers Added:
**Static Assets (/_next/static/*):**
**Static Assets (/\_next/static/\*):**
- `Cache-Control: public, max-age=31536000, immutable`
- 1 year cache for versioned assets
**Images (/images/*):**
**Images (/images/\*):**
- `Cache-Control: public, max-age=31536000, immutable`
### Experimental Features Enabled:
**next.config.js - experimental:**
- `staleTimes.dynamic: 30s` (client-side cache for dynamic pages)
- `staleTimes.static: 180s` (client-side cache for static pages)
- `optimizePackageImports` for react-markdown ecosystem
### Performance Impact:
- Reduced bandwidth usage
- Faster repeat visits (cached assets)
- Improved navigation speed (stale-while-revalidate)
@@ -137,18 +157,22 @@ Successfully implemented 7 categories of production optimizations for Next.js 16
## 7. Bundle Analyzer Setup
### Tools Installed:
- `@next/bundle-analyzer` (16.0.3)
### NPM Scripts Added:
- `npm run analyze` - Full bundle analysis
- `npm run analyze:server` - Server bundle only
- `npm run analyze:browser` - Browser bundle only
### Configuration:
- `next.config.analyzer.js` created
- Enabled with `ANALYZE=true` environment variable
### Usage:
```bash
npm run analyze
# Opens browser with bundle visualization
@@ -160,6 +184,7 @@ npm run analyze
## Bundle Size Analysis
### Static Assets:
```
Total Static: 1.2MB
- Largest chunks:
@@ -170,10 +195,12 @@ Total Static: 1.2MB
```
### Standalone Output:
- Total: 44MB (includes Node.js runtime, dependencies, server)
- Expected Docker image size: ~150MB (Alpine + Node.js + app)
### Bundle Composition:
- React + React-DOM: Largest dependencies
- react-markdown ecosystem: Second largest
- Next.js framework: Optimized with tree-shaking
@@ -183,6 +210,7 @@ Total Static: 1.2MB
## Build Verification
### Build Output:
```
Creating an optimized production build ...
✓ Compiled successfully in 3.9s
@@ -200,6 +228,7 @@ Route (app)
```
### Pre-rendered Pages:
- 19 static pages generated
- 3 blog posts
- 7 tag pages
@@ -210,6 +239,7 @@ Route (app)
## Files Modified/Created
### Modified:
- `Dockerfile.nextjs` (security hardening)
- `docker-compose.prod.yml` (security options)
- `next.config.js` (image optimization, caching headers)
@@ -217,6 +247,7 @@ Route (app)
- `package-lock.json` (dependency updates)
### Created:
- `app/sitemap.ts` (dynamic sitemap)
- `app/robots.ts` (robots.txt)
- `app/feed.xml/route.ts` (RSS feed)
@@ -227,6 +258,7 @@ Route (app)
## Performance Recommendations
### Implemented:
1. Bundle size reduced (11 packages removed)
2. Security hardened (Docker + CSP)
3. SEO optimized (sitemap + robots + RSS)
@@ -235,7 +267,8 @@ Route (app)
6. Bundle analyzer ready for monitoring
### Future Optimizations:
1. Consider CDN for static assets (/images, /_next/static)
1. Consider CDN for static assets (/images, /\_next/static)
2. Monitor bundle sizes with `npm run analyze` on each release
3. Add bundle size limits in CI/CD (fail if > threshold)
4. Consider Edge deployment for global performance
@@ -246,6 +279,7 @@ Route (app)
## Production Deployment Checklist
Before deploying:
- [ ] Set `NEXT_PUBLIC_SITE_URL` in production environment
- [ ] Verify Caddy reverse proxy configuration
- [ ] Test Docker build: `npm run docker:build`