DDARE Docs
Frontend

Frontend Deployment

Deploy to production: build the static bundle and serve dist/, with an optional Docker recipe.

Just want to run it locally? See QUICKSTART.md — npm install, set two env vars, npm run dev. That's the whole story for development. This guide is for deploying to production.

The DARE frontend is a static single-page app built with Vite. Deploying it is deliberately simple: build the bundle once, then serve the generated dist/ folder from any static host. There is no server runtime to manage.

For the full environment variable reference, see docs/configuration.md.


Prerequisites

RequirementVersionNotes
Node.js18+20 LTS recommended — build-time only
npm9+(or pnpm / yarn if you adapt scripts)
A running DARE backend—Reachable from the browser via the configured URLs

Node is needed only to build the bundle. Once you have dist/, the host serving it needs nothing but the ability to serve static files.


1. Configure environment

cp .env.example .env
# edit .env — see docs/configuration.md for the full reference

Minimum for a production build:

VITE_APP_ENVIRONMENT=production
VITE_DJANGO_BACKEND_URL=https://api.example.com
VITE_WEBSOCKET_URL=wss://api.example.com

Important: Vite inlines VITE_* values at build time. Changing them after the build has no effect — you must rebuild for each target environment.

2. Build

npm ci            # respect the lockfile
npm run build     # produces ./dist

dist/ is a self-contained static bundle: hashed JS/CSS assets plus index.html.

3. Serve dist/

Pick whichever fits your infrastructure — they are all equivalent from the app's point of view:

  • Managed static hosting (simplest) — upload dist/ to Netlify, Vercel, Cloudflare Pages, S3 + CloudFront, or Cloud Storage. The one required setting: SPA-style routing — rewrite all unmatched paths to /index.html so React Router can handle deep links.
  • Nginx / Apache / Caddy — copy dist/ to the web root and add the same SPA fallback. A minimal Nginx config is in the appendix below.
  • Quick check on a box — npx serve -s dist -l 5173 (the -s flag enables SPA fallback). Fine for staging; use a real web server or CDN for production.

4. CORS and CSRF

The backend must include the frontend's origin in CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS. See the backend configuration reference.

For Socket.IO to connect, VITE_WEBSOCKET_URL must be reachable from the browser and accept the same auth token used for REST.


Verifying the deployment

  1. Visit the deployed URL — the login screen should load.
  2. Open dev tools → Network, sign in, and confirm:
    • The REST request hits VITE_DJANGO_BACKEND_URL.
    • The Socket.IO upgrade succeeds (a wss:// request with a 101 status).
  3. Send a chat message — you should see streamed tokens arrive.
  4. Upload a file — it should move from processing to completed.

If any step fails, check the browser console for CORS or auth errors and confirm the backend's CORS_ALLOWED_ORIGINS includes your origin.


Upgrading

git pull
npm ci          # respect lockfile
npm run build
# redeploy dist/ via your usual mechanism

Appendix: Nginx & Docker

Serving a static bundle needs no container, so Docker is optional for the frontend — reach for it only if a container is how the rest of your stack ships. If so, a minimal multi-stage build:

# build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
ARG VITE_DJANGO_BACKEND_URL
ARG VITE_WEBSOCKET_URL
ENV VITE_DJANGO_BACKEND_URL=$VITE_DJANGO_BACKEND_URL
ENV VITE_WEBSOCKET_URL=$VITE_WEBSOCKET_URL
RUN npm run build

# serve stage
FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY devops/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

A SPA-friendly Nginx config (devops/nginx.conf) — also usable standalone, without Docker:

server {
    listen 80;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;

    # Cache static assets aggressively (they are content-hashed)
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # SPA fallback — let React Router handle the path
    location / {
        try_files $uri $uri/ /index.html;
    }
}

Build and run:

docker build \
    --build-arg VITE_DJANGO_BACKEND_URL=https://api.example.com \
    --build-arg VITE_WEBSOCKET_URL=wss://api.example.com \
    -t dare-frontend .

docker run -d -p 80:80 --name dare-frontend dare-frontend

Because Vite inlines VITE_* at build time, pass the per-environment URLs as build args — changing them on the running container has no effect.


Troubleshooting

SymptomLikely causeFix
White screen, console error about asset 404sServer not serving SPA fallback (deep links 404)Configure try_files $uri /index.html or the host's rewrite-to-index.html setting
Network Error on every requestWrong VITE_DJANGO_BACKEND_URL, or CORS not allowed by backendVerify URL; add origin to backend CORS_ALLOWED_ORIGINS
Chat connects but no streamed tokensSocket.IO URL or auth issueCheck VITE_WEBSOCKET_URL; inspect WS frames in dev tools
Build fails with TS errorsType drift after backend API changesUpdate redux/types/; run npx tsc --noEmit for a full report
Old code shipped after deployCDN or browser cacheEnsure index.html is Cache-Control: no-cache; assets fingerprinted (Vite default)
VITE_* env var ignored at runtimeVite inlines at build timeRebuild with the desired value

For local development, see QUICKSTART.md; for contributing, see CONTRIBUTING.md.

On this page