Files
sexy.pivoine.art/REBUILD_GUIDE.md
2025-10-26 14:48:30 +01:00

6.1 KiB

🔄 Rebuild Guide - When You Need to Rebuild the Image

Why Rebuild?

SvelteKit's PUBLIC_* environment variables are baked into the JavaScript at build time. You need to rebuild when:

  1. Changing PUBLIC_API_URL
  2. Changing PUBLIC_URL
  3. Changing PUBLIC_UMAMI_ID
  4. Changing any LETTERSPACE_* variables
  5. NOT needed for Directus env vars (those are runtime)

Quick Rebuild Process

1. Update Frontend Environment Variables

Edit the frontend .env file:

nano packages/frontend/.env

Set your production values:

PUBLIC_API_URL=https://sexy.pivoine.art/api
PUBLIC_URL=https://sexy.pivoine.art
PUBLIC_UMAMI_ID=your-umami-id
LETTERSPACE_API_URL=https://api.letterspace.com/v1
LETTERSPACE_API_KEY=your-key
LETTERSPACE_LIST_ID=your-list-id

2. Rebuild the Image

# From the project root
docker build -t ghcr.io/valknarxxx/sexy:latest -t sexy.pivoine.art:latest .

Expected Time: 30-45 minutes (first build), 10-15 minutes (cached rebuild)

3. Restart Services

# If using docker-compose
cd /home/valknar/Projects/docker-compose/sexy
docker compose down
docker compose up -d

# Or directly
docker stop sexy_frontend
docker rm sexy_frontend
docker compose up -d frontend

Monitoring the Build

Check Build Progress

# Watch build output
docker build -t ghcr.io/valknarxxx/sexy:latest .

# Build stages:
# 1. Base (~30s) - Node.js setup
# 2. Builder (~25-40min) - Rust + WASM + packages
#    - Rust installation: ~2-3 min
#    - wasm-bindgen-cli: ~10-15 min
#    - WASM build: ~5-10 min
#    - Package builds: ~5-10 min
# 3. Runner (~2min) - Final image assembly

Verify Environment Variables in Built Image

# Check what PUBLIC_API_URL is baked in
docker run --rm ghcr.io/valknarxxx/sexy:latest sh -c \
  "grep -r 'PUBLIC_API_URL' /home/node/app/packages/frontend/build/ | head -3"

# Should show: https://sexy.pivoine.art/api

Push to GitHub Container Registry

After successful build:

# Login to GHCR (first time only)
echo $GITHUB_TOKEN | docker login ghcr.io -u valknarxxx --password-stdin

# Push the image
docker push ghcr.io/valknarxxx/sexy:latest

Alternative: Build Arguments (Future Enhancement)

To avoid rebuilding for every env change, consider adding build arguments:

# In Dockerfile, before building frontend:
ARG PUBLIC_API_URL=https://sexy.pivoine.art/api
ARG PUBLIC_URL=https://sexy.pivoine.art
ARG PUBLIC_UMAMI_ID=

# Create .env.production dynamically
RUN echo "PUBLIC_API_URL=${PUBLIC_API_URL}" > packages/frontend/.env.production && \
    echo "PUBLIC_URL=${PUBLIC_URL}" >> packages/frontend/.env.production && \
    echo "PUBLIC_UMAMI_ID=${PUBLIC_UMAMI_ID}" >> packages/frontend/.env.production

Then build with:

docker build \
  --build-arg PUBLIC_API_URL=https://sexy.pivoine.art/api \
  --build-arg PUBLIC_URL=https://sexy.pivoine.art \
  -t ghcr.io/valknarxxx/sexy:latest .

Troubleshooting

Build Fails at Rust Installation

# Check network connectivity
ping -c 3 sh.rustup.rs

# Build with verbose output
docker build --progress=plain -t ghcr.io/valknarxxx/sexy:latest .

Build Fails at WASM

# Check if wasm-bindgen-cli matches package.json version
docker run --rm rust:latest cargo install wasm-bindgen-cli --version 0.2.103

Frontend Still Shows Wrong URL

# Verify .env file is correct
cat packages/frontend/.env

# Check if old image is cached
docker images | grep sexy
docker rmi ghcr.io/valknarxxx/sexy:old-tag

# Force rebuild without cache
docker build --no-cache -t ghcr.io/valknarxxx/sexy:latest .

Container Starts But Can't Connect to API

  1. Check Traefik routing:
docker logs traefik | grep sexy
  1. Check if Directus is accessible:
curl -I https://sexy.pivoine.art/api/server/health
  1. Check frontend logs:
docker logs sexy_frontend

Development vs Production

Development (Local)

  • Use pnpm dev for hot reload
  • No rebuild needed for code changes
  • Env vars from .env or shell

Production (Docker)

  • Rebuild required for PUBLIC_* changes
  • Changes baked into JavaScript
  • Env vars from packages/frontend/.env

Optimization Tips

Speed Up Rebuilds

  1. Use BuildKit cache:
export DOCKER_BUILDKIT=1
docker build --build-arg BUILDKIT_INLINE_CACHE=1 -t ghcr.io/valknarxxx/sexy:latest .
  1. Multi-stage caching:
  • Dockerfile already optimized with multi-stage build
  • Dependencies cached separately from code
  1. Parallel builds:
# Build with more CPU cores
docker build --cpus 4 -t ghcr.io/valknarxxx/sexy:latest .

Reduce Image Size

Current optimizations:

  • Multi-stage build
  • Production dependencies only
  • Minimal base image
  • No dev tools in final image

Expected sizes:

  • Base: ~100MB
  • Builder: ~2-3GB (not shipped)
  • Runner: ~300-500MB (final)

Automation

GitHub Actions (Already Set Up)

The .github/workflows/docker-build-push.yml automatically:

  1. Builds on push to main
  2. Creates version tags
  3. Pushes to GHCR
  4. Caches layers for faster builds

Trigger a rebuild:

git tag v1.0.1
git push origin v1.0.1

Local Build Script

Use the provided build.sh:

./build.sh -t v1.0.0 -p

When NOT to Rebuild

You DON'T need to rebuild for:

  • Directus configuration changes
  • Database credentials
  • Redis settings
  • SMTP settings
  • Session cookie settings
  • Traefik labels

These are runtime environment variables and can be changed in docker-compose.

Summary

Change Rebuild Needed How to Apply
PUBLIC_API_URL Yes Rebuild image
PUBLIC_URL Yes Rebuild image
PUBLIC_UMAMI_ID Yes Rebuild image
LETTERSPACE_* Yes Rebuild image
SEXY_DIRECTUS_* No Restart container
DB_* No Restart container
EMAIL_* No Restart container
Traefik labels No Restart container

Remember: The key difference is build-time (compiled into JS) vs runtime (read from environment).