From 7b1af5a8effb76207b885357ba98e42c5893b715 Mon Sep 17 00:00:00 2001 From: Aravind Date: Mon, 10 Aug 2026 14:37:51 +0530 Subject: [PATCH] add dockerfile --- .dockerignore | 25 +++++++++++++++++++ Dockerfile | 32 +++++++++++++++++++++++++ nginx.conf | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ vite.config.js | 15 ++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..53cf7ac --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +node_modules +dist +dist-ssr + +.git +.gitignore + +.env +.env* +*.local + +*.log +npm-debug.log* +yarn-debug.log* +pnpm-debug.log* + +.DS_Store +.vscode +.idea +.claude +.vite + +README.md +Dockerfile +.dockerignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9be98aa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# ---- Build stage ---- +FROM node:22-alpine AS build + +WORKDIR /app + +# Safety valve for the 2 GB host: without a cap a runaway build can exhaust the +# server's RAM and take down neighbouring containers. Measured peak for this app +# is ~550 MB, so 1 GB leaves headroom while still failing the build rather than +# the server. Raise this only if the host gets more RAM. +ENV NODE_OPTIONS=--max-old-space-size=1024 + +# Install deps from the lockfile first so this layer is reused when only src changes +COPY package.json package-lock.json ./ +RUN npm ci --no-audit --no-fund + +COPY . . +RUN npm run build + +# ---- Runtime stage ---- +FROM nginx:alpine + +# Remove Nginx's default "Welcome" page files completely +RUN rm -rf /usr/share/nginx/html/* + +# Only the compiled assets reach the final image — no node_modules, no source +COPY --from=build /app/dist /usr/share/nginx/html + +COPY nginx.conf /etc/nginx/nginx.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..cb40136 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,65 @@ +user nginx; +worker_processes auto; + +error_log /dev/stderr warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /dev/stdout; + + sendfile on; + tcp_nopush on; + keepalive_timeout 65; + server_tokens off; + + # Compression: takes the main JS bundle from ~1.9 MB down to ~530 kB on the wire + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_min_length 1024; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/json + application/xml + image/svg+xml + font/woff + font/woff2; + + server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # Vite writes content-hashed filenames here, so they can be cached forever. + # Only add_header is used — combining it with `expires` emits two + # conflicting Cache-Control headers. + location /assets/ { + add_header Cache-Control "public, max-age=31536000, immutable"; + access_log off; + } + + # index.html must be revalidated every time or deploys won't take effect + location = /index.html { + add_header Cache-Control "no-cache"; + } + + location / { + # This line forces Nginx to pass routing back to React Router + try_files $uri $uri/ /index.html; + } + } +} diff --git a/vite.config.js b/vite.config.js index ad20890..5c2467f 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,6 +11,21 @@ export default defineConfig({ '@': path.resolve(import.meta.dirname, './src'), }, }, + build: { + rollupOptions: { + output: { + // Split the heavy libraries out of the app bundle. They change far less + // often than app code, so browsers keep them cached across deploys. + manualChunks: { + react: ['react', 'react-dom', 'react-router-dom'], + charts: ['recharts'], + motion: ['framer-motion'], + markdown: ['react-markdown'], + canvas: ['html2canvas'], + }, + }, + }, + }, server: { // Honor a port assigned by the environment; fall back to Vite's default. port: process.env.PORT ? Number(process.env.PORT) : 5173,