diff --git a/Dockerfile b/Dockerfile index 19c6b2f..b9e8ff2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,37 @@ -FROM node:22-bookworm-slim +# ============================================ +# Stage 1: Builder +# ============================================ +FROM node:22-bookworm-slim AS builder + +WORKDIR /app + +# Copy package files for dependency installation +COPY package*.json tsconfig.json ./ + +# Install ALL dependencies (including devDependencies for build) +RUN npm install + +# Copy source code and build scripts +COPY src/ src/ +COPY scripts/ scripts/ +COPY public/ public/ + +# Compile TypeScript +RUN npx tsc + +# Generate OpenAPI spec +RUN node scripts/generate-openapi.mjs + +# Build HTML templates +RUN node scripts/build-html.cjs + +# Create swagger-ui symlink in builder stage +RUN rm -f public/swagger-ui && ln -s /app/node_modules/swagger-ui-dist public/swagger-ui + +# ============================================ +# Stage 2: Production +# ============================================ +FROM node:22-bookworm-slim AS production # Install Chromium and dependencies as root RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -9,25 +42,25 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN groupadd --gid 1001 docfast \ && useradd --uid 1001 --gid docfast --shell /bin/bash --create-home docfast -# Set environment variables +WORKDIR /app + +# Copy package files for production dependency installation +COPY package*.json ./ + +# Install ONLY production dependencies +RUN npm install --omit=dev + +# Copy compiled artifacts from builder stage +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/public ./public + +# Recreate swagger-ui symlink in production stage +RUN rm -f public/swagger-ui && ln -s /app/node_modules/swagger-ui-dist public/swagger-ui + +# Set Puppeteer environment variables ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium -# Build stage - compile TypeScript -WORKDIR /app -COPY package*.json tsconfig.json ./ -RUN npm install -COPY src/ src/ -RUN npx tsc - -# Remove dev dependencies -RUN npm prune --omit=dev -COPY scripts/ scripts/ -COPY public/ public/ -RUN node scripts/generate-openapi.mjs -RUN node scripts/build-html.cjs -RUN rm -f public/swagger-ui && ln -s /app/node_modules/swagger-ui-dist public/swagger-ui - # Create data directory and set ownership to docfast user RUN mkdir -p /app/data && chown -R docfast:docfast /app diff --git a/src/__tests__/dockerfile-build.test.ts b/src/__tests__/dockerfile-build.test.ts new file mode 100644 index 0000000..27468df --- /dev/null +++ b/src/__tests__/dockerfile-build.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from "vitest"; +import { existsSync } from "fs"; +import { resolve } from "path"; + +describe("Dockerfile Build Artifacts", () => { + it("should have compiled dist/index.js from TypeScript build", () => { + // This verifies that the TypeScript compilation step in the Dockerfile worked + const distPath = resolve(process.cwd(), "dist", "index.js"); + expect( + existsSync(distPath), + "dist/index.js should exist after TypeScript compilation" + ).toBe(true); + }); + + it("should have built public/index.html from build script", () => { + // This verifies that the HTML template build step in the Dockerfile worked + const publicPath = resolve(process.cwd(), "public", "index.html"); + expect( + existsSync(publicPath), + "public/index.html should exist after build-html script runs" + ).toBe(true); + }); +});