# syntax=docker/dockerfile:1 # ============================================================================= # Node.js 22 - Frontend Classeo (SvelteKit) # ============================================================================= FROM node:22-alpine AS base # Install pnpm RUN corepack enable && corepack prepare pnpm@10.28.2 --activate # Configure pnpm to use a directory inside the project (works with volume mounts) ENV PNPM_HOME=/app/.pnpm-store ENV PATH="$PNPM_HOME:$PATH" # Set working directory WORKDIR /app # ============================================================================= # Development stage # ============================================================================= FROM base AS dev # Install gosu for proper user switching ENV GOSU_VERSION=1.17 RUN set -eux; \ apk add --no-cache --virtual .gosu-deps dpkg gnupg; \ dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ chmod +x /usr/local/bin/gosu; \ gosu --version; \ gosu nobody true; \ apk del --no-network .gosu-deps # Entrypoint: detect host UID/GID and run as matching user # Uses gosu with UID:GID directly (no need to create user in Dockerfile) COPY --chmod=755 <<'EOF' /usr/local/bin/docker-entrypoint.sh #!/bin/sh set -e # Detect UID/GID from mounted /app directory HOST_UID=$(stat -c %u /app) HOST_GID=$(stat -c %g /app) # If root owns /app, run as root (CI environment or volume not mounted) if [ "$HOST_UID" = "0" ]; then # Install dependencies if not present if [ ! -d /app/node_modules ] || [ ! -f /app/node_modules/.pnpm/lock.yaml ]; then echo "Installing pnpm dependencies..." pnpm install fi exec "$@" fi # Fix node_modules volume ownership (Docker creates volumes as root) # This only takes time on first run when the volume is empty if [ -d /app/node_modules ] && [ "$(stat -c %u /app/node_modules)" = "0" ]; then echo "Fixing node_modules ownership..." chown -R "$HOST_UID:$HOST_GID" /app/node_modules fi # Ensure pnpm store directory exists and is writable mkdir -p /app/.pnpm-store chown "$HOST_UID:$HOST_GID" /app/.pnpm-store # Install pnpm dependencies if not present (as host user) if [ ! -d /app/node_modules/.pnpm ]; then echo "Installing pnpm dependencies..." gosu "$HOST_UID:$HOST_GID" pnpm install fi # Run command as host user via gosu (using UID:GID directly) exec gosu "$HOST_UID:$HOST_GID" "$@" EOF EXPOSE 5173 ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["pnpm", "run", "dev", "--host", "0.0.0.0"] # ============================================================================= # Build stage # ============================================================================= FROM base AS builder COPY package.json pnpm-lock.yaml* ./ RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; else pnpm install; fi COPY . . RUN pnpm run build # ============================================================================= # Production stage # ============================================================================= FROM base AS prod ENV NODE_ENV=production COPY package.json pnpm-lock.yaml* ./ RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile --prod; else pnpm install --prod; fi COPY --from=builder /app/build build/ COPY --from=builder /app/package.json . EXPOSE 3000 CMD ["node", "build"]