# syntax=docker/dockerfile:1.7 ARG APP_VERSION=4.0.1 FROM node:22-alpine AS builder ARG APP_VERSION WORKDIR /app # 1. Dependencies — only re-runs when package*.json change. COPY package.json package-lock.json ./ RUN npm ci # 2. Image assets in their own layer. Enhanced-img content-hashes its inputs, # so when these files are unchanged the BuildKit cache mount below replays # the previous WebP/AVIF outputs instead of regenerating them. COPY src/lib/images ./src/lib/images COPY static ./static # 3. Build config (changes rarely). COPY svelte.config.js vite.config.ts tsconfig.json ./ # 4. Everything else. Component-only edits invalidate this layer but the vite # transform cache below keeps the expensive image pipeline warm. COPY . . RUN node --experimental-strip-types --import="file:///app/scripts/sveltekit-resolver.mjs" scripts/export-homepage-content.mjs # Persist vite's transform cache across builds. Enhanced-img stores its # generated raster variants here keyed by source-image hash, so unchanged # images skip the sharp/resize/encode pass entirely. RUN --mount=type=cache,target=/app/node_modules/.vite,sharing=locked \ npm run build FROM node:22-alpine AS runner ARG APP_VERSION WORKDIR /app ENV NODE_ENV=production ENV APP_VERSION=${APP_VERSION} LABEL org.opencontainers.image.version="${APP_VERSION}" COPY --from=builder /app/package.json ./ COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/build ./build COPY --from=builder /app/scripts/sync-homepage-content.mjs ./scripts/sync-homepage-content.mjs COPY --from=builder /app/deploy-data/homepage-content.json ./deploy-data/homepage-content.json EXPOSE 3000 CMD ["node", "build"]