Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions frontend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
dist
e2e
playwright-report
test-results
*.tsbuildinfo
.env
.env.*
.DS_Store
npm-debug.log*
41 changes: 41 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Multi-stage build: Node build stage + nginx runtime stage
# Docs: https://vite.dev/guide/static-deploy

# ---------- Build stage ----------
FROM node:20-alpine AS builder

WORKDIR /app

# Install dependencies first for better layer caching
COPY package.json package-lock.json ./
RUN npm ci

# Copy source and build
COPY . .

# Build the static site (tsc + vite build)
ARG VITE_API_URL
ARG VITE_STELLAR_NETWORK
ARG VITE_STELLAR_NETWORK_PASSPHRASE
ARG VITE_STELLAR_HORIZON_URL
ENV VITE_API_URL=${VITE_API_URL} \
VITE_STELLAR_NETWORK=${VITE_STELLAR_NETWORK} \
VITE_STELLAR_NETWORK_PASSPHRASE=${VITE_STELLAR_NETWORK_PASSPHRASE} \
VITE_STELLAR_HORIZON_URL=${VITE_STELLAR_HORIZON_URL}

RUN npm run build

# ---------- Runtime stage ----------
FROM nginx:1.27-alpine AS production

# SPA routing with fallback to index.html + caching headers
COPY nginx.conf /etc/nginx/conf.d/default.conf

COPY --from=builder /app/dist /usr/share/nginx/html

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost/ > /dev/null || exit 1

CMD ["nginx", "-g", "daemon off;"]
29 changes: 29 additions & 0 deletions frontend/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
server {
listen 80;
server_name _;

root /usr/share/nginx/html;
index index.html;

# Gzip static assets
gzip on;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
gzip_min_length 1024;

# Hashed assets (js/css with content hash) — cache forever
location ~* \.(?:js|css|png|jpg|jpeg|gif|webp|avif|svg|ico|woff2?)$ {
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable";
try_files $uri =404;
}

# index.html — never cache so deploys propagate immediately
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
}

# SPA routing — fall back to index.html for client-side routes
location / {
try_files $uri $uri/ /index.html;
}
}