diff --git a/Dockerfile b/Dockerfile index ad0c1a2..d7d4f10 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,71 @@ -FROM node:lts AS builder +# Multi-stage build optimized for maximum build speed +# This version uses a Chrome-enabled base for fastest rebuilds + +# Stage 1: Chrome base (cached once, reused forever) +FROM node:18-slim AS chrome-base +RUN apt-get update && apt-get install -y --no-install-recommends \ + wget gnupg ca-certificates \ + && wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \ + && apt-get update && apt-get install -y --no-install-recommends \ + google-chrome-stable \ + fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 \ + libcairo2 libcups2 libdbus-1-3 libdrm2 libgtk-3-0 libnspr4 \ + libnss3 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \ + libxss1 libxtst6 lsb-release xdg-utils \ + && rm -rf /var/lib/apt/lists/* && apt-get clean + +# Stage 2: Dependencies (cached when package.json unchanged) +FROM chrome-base AS deps +WORKDIR /app +RUN npm i -g pnpm +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# Stage 3: Builder (only rebuilds when source changes) +FROM deps AS builder +COPY . . +RUN pnpm run build + +# Stage 4: Production dependencies (cached separately) +FROM chrome-base AS prod-deps +WORKDIR /app +RUN npm i -g pnpm +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --prod --frozen-lockfile && pnpm store prune + +# Stage 5: Runtime (fastest layer, only copies artifacts) +FROM chrome-base AS runtime +WORKDIR /app + +# Create user (cached) +RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \ + && mkdir -p /home/pptruser/Downloads \ + && chown -R pptruser:pptruser /home/pptruser + +# Copy artifacts (only changes when build changes) +COPY --from=builder /app/dist ./dist +COPY --from=prod-deps /app/node_modules ./node_modules +COPY --from=prod-deps /app/package.json ./package.json + +# Set ownership and environment +RUN chown -R pptruser:pptruser /app +ENV HOST=0.0.0.0 \ + PORT=4321 \ + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ + PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable \ + NODE_ENV=production + +USER pptruser +EXPOSE 4321 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "const http = require('http'); const options = { host: 'localhost', port: 4321, timeout: 2000 }; const req = http.request(options, (res) => { process.exit(res.statusCode === 200 ? 0 : 1); }); req.on('error', () => process.exit(1)); req.end();" + +CMD ["node", "./dist/server/entry.mjs"] + +FROM node:18-slim AS builder + WORKDIR /app # Install pnpm