From a76b371bda58954bba1af3d62e0f0870c5ffb705 Mon Sep 17 00:00:00 2001 From: Greg Date: Sun, 17 Aug 2025 01:01:31 +0200 Subject: [PATCH] dockerized version instead of nixpack --- .dockerignore | 11 +++++++++++ Dockerfile | 28 ++++++++++++++++++++++++++++ README.md | 34 ++++++++++++++++++---------------- docker/nginx.conf | 18 ++++++++++++++++++ package.json | 4 +--- src/App.tsx | 3 +-- 6 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker/nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4da58da --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +node_modules +dist +.git +.vscode +.idea +.DS_Store +.env +npm-debug.log* +yarn-*.log* +pnpm-debug.log* +docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..99fb2ae --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +# syntax=docker/dockerfile:1.7 +ARG NODE_VERSION=20.15.0 +FROM node:${NODE_VERSION}-alpine AS build +WORKDIR /app + +# Install deps first for better caching +COPY package*.json ./ +RUN npm ci || npm install + +# Build +COPY . . +ENV NODE_ENV=production +# Limit Node heap during build to avoid OOM on small builders +ENV NODE_OPTIONS=--max-old-space-size=512 +RUN npm run build + +# ---- Runtime (Nginx) ---- +FROM nginx:1.27-alpine AS runtime +# Remove default site content +RUN rm -rf /usr/share/nginx/html/* +# SPA config (history fallback) +COPY docker/nginx.conf /etc/nginx/conf.d/default.conf +# Static assets +COPY --from=build /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 2>&1 || exit 1 +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 57e9d1f..93ea358 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,31 @@ -# Reading Goal App +# Reading Goal App (Dockerized) -A React + Vite + Tailwind single-page app. Dates are DD/MM/YYYY everywhere and the calendar starts on Monday. - -## Local Development +React + Vite + Tailwind. Dates use **DD/MM/YYYY** and the calendar week starts on **Monday**. +Includes a multi-stage Dockerfile: Node build → Nginx runtime with SPA fallback. +## Local Dev ```bash npm install npm run dev ``` -## Production Build - +## Production Build (local) ```bash npm run build npm run preview ``` -## Deploy with Coolify (Nixpacks) +## Docker (build locally) +```bash +docker build -t reading-goal-app:latest . +docker run -d --name reading-goal-app -p 8080:80 --restart unless-stopped reading-goal-app:latest +# Open http://localhost:8080 +``` -1. Push this repo to GitHub. -2. In Coolify: **Create Application → Git**, select your repo/branch. -3. **Build Pack**: choose **Nixpacks**. -4. No base directory unless you're using a monorepo. -5. (Optional) **Environment**: set `NODE_ENV=production`. -6. Deploy. The container will: - - install dependencies - - build with `vite build` (output in `dist/`) - - run `serve -s dist -l $PORT` (Coolify injects `$PORT`) +## Deploy in Coolify +- Deployment Type: **Dockerfile** +- Dockerfile path: `Dockerfile` +- **Internal Port**: `80` (Nginx) +- No extra start command needed. + +The multi-stage image builds the app (`vite build`) and serves static files via Nginx with history API fallback. diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..3a2f3e9 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,18 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Serve files if they exist, else fallback to index.html (SPA) + location / { + try_files $uri $uri/ /index.html; + } + + # Static assets (cache-friendly) + location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|ico|woff2?)$ { + expires 30d; + add_header Cache-Control "public, immutable"; + try_files $uri /index.html; + } +} diff --git a/package.json b/package.json index 8965c99..02f05bc 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,7 @@ "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview --host 0.0.0.0 --port 5173", - "start": "serve -s dist -l ${PORT:-3000}" + "preview": "vite preview --host 0.0.0.0 --port 5173" }, "dependencies": { "lucide-react": "^0.452.0", @@ -20,7 +19,6 @@ "@vitejs/plugin-react": "^4.2.0", "autoprefixer": "^10.4.18", "postcss": "^8.4.33", - "serve": "^14.2.1", "tailwindcss": "^3.4.9", "typescript": "^5.5.4", "vite": "^5.3.4" diff --git a/src/App.tsx b/src/App.tsx index b07d24c..4d911ec 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,3 @@ - import React, { useEffect, useState } from 'react'; import { BookOpen, Plus, X, Edit2, Check, ChevronLeft, ChevronRight } from 'lucide-react'; @@ -598,7 +597,7 @@ const ReadingGoalApp = () => {

Progress Overview

Current Progress{book.currentPage} / {book.totalPages} pages
-
+
Completion{progressPercent.toFixed(1)}%