cd frontend/
docker pull ubuntu:24.04# build the container
docker compose build dev
# external to internal port -- default 9022:9021 specified in docker-compose.yml
docker compose run -p 9022:9021 devcurrently, docker-compose.yml only has one service: dev
services:
dev:
build: .
volumes:
- ./frontend:/app/frontend
working_dir: /app/frontend
command: sh -c ". /app/venv/bin/activate && npm install && npm run dev"
ports:
- "9022:9021"Question 1: How does one build a production version of a react app they usually use npm run build to run?
Recall that we have a vite.config.js and a package.json and a package-lock.json in the frontend directory.
We must observe which tools are being used to build the app and then use those tools.
For instance, the existence of the express.js application and the python subprocess spawning means that parts of the application that are run with the npm run dev
Question 2: Can one just slot in npm run build-and-serve as the command in the docker-compose.yml file for an exact copy of the dev service as prod? Why or why not?
Take careful note of the existing code to inform your answers.
- Docker ≥ 24
- Node ≥ 18 (only if you want to run locally outside containers)
- Python 3.8+ with dependencies:
pip install -r requirements.txt - ffmpeg for audio processing
- API keys set in
.env(seeSETUP.md):- GEMINI_API_KEY (required for speaker extraction tool)
- OPENAI_API_KEY, ANTHROPIC_API_KEY (for bio generation)
- ELEVENLABS_API_KEY (optional, for voice synthesis)
# Build once (re-runs only when Dockerfile changes)
docker compose build dev
# Start container with Vite + Express live-reload
# Exposes 9021 inside the container → 9022 on host
# Visit http://localhost:9022
docker compose up devLive changes under frontend/ are mounted into the container via the volume, so edits refresh instantly.
# Build image – runs `npm ci && npm run build` inside Dockerfile
# and bakes the optimised React bundle into /app/frontend/dist
docker compose build prod
# Start detached
# Exposes Express on container port 3001 → 3001 on host
# Visit http://localhost:3001
docker compose up -d prodKey differences:
- No volume mount – code is baked into the image; ensures predictable builds.
- Single server – Express (
server.js) serves both API and static assets. - Ports –
devuses Vite on 9021;produses Express on 3001.
docker compose run --rm prod ls -R /app/frontend/dist | headYou should see index.html, assets/*.js, and assets/*.css.
| Symptom | Likely cause | Fix |
|---|---|---|
Browser console shows MIME type "text/html" for JS files |
Request for *.js hit SPA fallback and returned index.html |
Ensure dist/ exists and express.static(distPath) is above the wildcard app.get('*') route. |
404 for /api/* in production |
Wrong port (trying 9022) | Use http://localhost:3001 in prod. |
| Frontend extremely stale | Forgot to rebuild image | docker compose build prod then docker compose up -d prod. |
docker compose down # stop & remove containers
docker image prune -f # optional: cleanup dangling layersWith these commands the same codebase can be iterated on rapidly in dev and shipped as a lean, reproducible image in prod.