From b3157fffbd2451b5ce4d8fab82b93ec2c725f2d6 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sat, 29 Nov 2025 12:15:19 +0100 Subject: [PATCH] feat: update Next.js configuration to enable standalone output for improved deployment --- .dockerignore | 46 ++++++++++++++++++++++++++++++ Dockerfile | 66 +++++++++++++++++++++++++++++++++++++++++++ data/dev.db | Bin 0 -> 233472 bytes data/prod.db | Bin 0 -> 188416 bytes docker-compose.yml | 17 +++++++++++ docker-entrypoint.sh | 9 ++++++ next.config.ts | 2 +- 7 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 data/dev.db create mode 100644 data/prod.db create mode 100644 docker-compose.yml create mode 100644 docker-entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..82eeb26 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# Dependencies +node_modules +.pnpm-store + +# Build outputs +.next +out +dist +build + +# Database +*.db +*.db-journal +data/ + +# Git +.git +.gitignore + +# IDE +.idea +.vscode +*.swp +*.swo + +# Misc +*.log +npm-debug.log* +.DS_Store +Thumbs.db + +# Environment +.env +.env.* +!.env.example + +# Docker +Dockerfile* +docker-compose* +.dockerignore + +# Documentation +README.md +devbook.md +TODO.md + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a3f0cc1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,66 @@ +# syntax=docker/dockerfile:1 + +# ---- Base ---- +FROM node:22-alpine AS base +RUN corepack enable && corepack prepare pnpm@latest --activate +WORKDIR /app + +# ---- Dependencies ---- +FROM base AS deps +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# ---- Build ---- +FROM base AS builder +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Generate Prisma client (dummy URL for build, actual URL at runtime) +ENV DATABASE_URL="file:/tmp/build.db" +RUN pnpm prisma generate + +# Build Next.js +ENV NEXT_TELEMETRY_DISABLED=1 +RUN pnpm build + +# ---- Production ---- +FROM base AS runner +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +# Install build tools for native modules (better-sqlite3) +RUN apk add --no-cache python3 make g++ + +# Create non-root user +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +# Copy built assets (standalone includes node_modules needed for runtime) +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +# Copy Prisma schema, migrations, and config +COPY --from=builder /app/prisma ./prisma +COPY --from=builder /app/prisma.config.ts ./prisma.config.ts + +# Install prisma CLI for migrations + better-sqlite3 (compile native module) +ENV DATABASE_URL="file:/app/data/prod.db" +RUN pnpm add prisma @prisma/client @prisma/adapter-better-sqlite3 better-sqlite3 dotenv && \ + pnpm prisma generate + +# Copy entrypoint script +COPY --chown=nextjs:nodejs docker-entrypoint.sh ./ +RUN chmod +x docker-entrypoint.sh + +# Create data directory for SQLite +RUN mkdir -p /app/data && chown -R nextjs:nodejs /app/data + +USER nextjs + +EXPOSE 3000 +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" +ENV DATABASE_URL="file:/app/data/prod.db" + +ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/data/dev.db b/data/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..156f36c782476ed52515c21755d231aa1f9c376d GIT binary patch literal 233472 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 CWXe|n literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..37feebf --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "3011:3000" + environment: + - NODE_ENV=production + - DATABASE_URL=file:/app/data/dev.db + - AUTH_SECRET=${AUTH_SECRET:-your-secret-key-change-in-production} + - AUTH_TRUST_HOST=true + - AUTH_URL=${AUTH_URL:-http://localhost:3011} + volumes: + - ./data:/app/data + restart: unless-stopped + diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..781a1fd --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +echo "🔄 Running database migrations..." +pnpm prisma migrate deploy + +echo "🚀 Starting application..." +exec node server.js + diff --git a/next.config.ts b/next.config.ts index e9ffa30..68a6c64 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + output: "standalone", }; export default nextConfig;