diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..937bc58 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,40 @@ +# Version control +.git +.github +.gitignore + +# Dependencies +node_modules +npm-debug.log +yarn-debug.log +yarn-error.log + +# Environment +.env.local +.env.development.local +.env.test.local +.env.production.local +.env + +# Next.js build output +.next/cache + +# Testing +coverage +__tests__ +*.test.js +*.spec.js + +# Development files +README.md +*.md +.editorconfig +.eslintrc +.prettierrc +.vscode +docs + +# OS specific +.DS_Store +Thumbs.db +*.swp \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..038a504 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# Stage 1: Dependencies +FROM node:18-alpine AS deps + +# Set working directory +WORKDIR /app + +# Copy package files first for better caching +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ + +# Install dependencies based on the lockfile +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Stage 2: Build the application +FROM node:18-alpine AS builder + +# Set working directory +WORKDIR /app + +# Copy dependencies from deps stage +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Build the application +RUN npm run build + +# Stage 3: Production image +FROM node:18-alpine AS runner +WORKDIR /app + +# Don't run production as root +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +USER nextjs + +# Copy built assets from builder +COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next +COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules +COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json +COPY --from=builder --chown=nextjs:nodejs /app/public ./public + +# Next.js collects completely anonymous telemetry data +ENV NEXT_TELEMETRY_DISABLED 1 + +# Expose port and start the application +EXPOSE 3000 +ENV PORT 3000 +ENV NODE_ENV production + +CMD ["npm", "start"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f37af7a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,47 @@ +version: "3.8" + +services: + # Development service + nextjs-dev: + build: + context: . + target: deps + dockerfile: Dockerfile + volumes: + - app-code:/app + - /app/node_modules + - /app/.next + ports: + - "3000:3000" + environment: + - NODE_ENV=development + - WATCHPACK_POLLING=true + - CHOKIDAR_USEPOLLING=true + - NEXT_WEBPACK_POLLING=true + command: npm run dev + profiles: ["dev"] + # Add these settings for better file watching + init: true + stdin_open: true + tty: true + + # Production service + nextjs-prod: + build: + context: . + target: runner + dockerfile: Dockerfile + restart: unless-stopped + ports: + - "3000:3000" + environment: + - NODE_ENV=production + profiles: ["prod"] + +volumes: + app-code: + driver: local + driver_opts: + type: none + o: bind + device: ${PWD} diff --git a/package.json b/package.json index 0307c4d..3165f59 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "docker:dev": "docker-compose --profile dev up", + "docker:prod": "docker-compose --profile prod up -d" }, "dependencies": { "@emailjs/browser": "^4.4.1",