diff --git a/Dockerfile b/Dockerfile index 46f86ba..5c3a236 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,69 @@ -FROM node:22-bookworm-slim +ARG PLAYWRIGHT_BROWSERS_PATH=/ms-playwright + +# ------------------------------ +# Base +# ------------------------------ +# Base stage: Contains only the minimal dependencies required for runtime +# (node_modules and Playwright system dependencies) +FROM node:22-bookworm-slim AS base + +ARG PLAYWRIGHT_BROWSERS_PATH +ENV PLAYWRIGHT_BROWSERS_PATH=${PLAYWRIGHT_BROWSERS_PATH} # Set the working directory WORKDIR /app -# Copy package.json and package-lock.json at this stage to leverage the build cache -COPY package*.json ./ +RUN --mount=type=cache,target=/root/.npm,sharing=locked,id=npm-cache \ + --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=package-lock.json,target=package-lock.json \ + npm ci --omit=dev && \ + # Install system dependencies for playwright + npx -y playwright-core install-deps chromium -# Install dependencies -RUN npm ci +# ------------------------------ +# Builder +# ------------------------------ +FROM base AS builder -# Install chromium and its dependencies, but only for headless mode -RUN npx -y playwright install --with-deps --only-shell chromium +RUN --mount=type=cache,target=/root/.npm,sharing=locked,id=npm-cache \ + --mount=type=bind,source=package.json,target=package.json \ + --mount=type=bind,source=package-lock.json,target=package-lock.json \ + npm ci # Copy the rest of the app -COPY . . +COPY *.json *.js *.ts . +COPY src src/ # Build the app RUN npm run build +# ------------------------------ +# Browser +# ------------------------------ +# Cache optimization: +# - Browser is downloaded only when node_modules or Playwright system dependencies change +# - Cache is reused when only source code changes +FROM base AS browser + +RUN npx -y playwright-core install --no-shell chromium + +# ------------------------------ +# Runtime +# ------------------------------ +FROM base + +ARG PLAYWRIGHT_BROWSERS_PATH +ARG USERNAME=node +ENV NODE_ENV=production + +# Set the correct ownership for the runtime user on production `node_modules` +RUN chown -R ${USERNAME}:${USERNAME} node_modules + +USER ${USERNAME} + +COPY --from=browser --chown=${USERNAME}:${USERNAME} ${PLAYWRIGHT_BROWSERS_PATH} ${PLAYWRIGHT_BROWSERS_PATH} +COPY --chown=${USERNAME}:${USERNAME} cli.js package.json ./ +COPY --from=builder --chown=${USERNAME}:${USERNAME} /app/lib /app/lib + # Run in headless and only with chromium (other browsers need more dependencies not included in this image) -ENTRYPOINT ["node", "cli.js", "--headless", "--browser", "chromium"] \ No newline at end of file +ENTRYPOINT ["node", "cli.js", "--headless", "--browser", "chromium"]