FE_Dev / Dockerfile
GitHub Actions
Deploy from GitHub Actions [dev] - 2025-10-31 07:28:50
68f7925
# syntax=docker.io/docker/dockerfile:1
# Force cache invalidation for HuggingFace Spaces
ARG CACHEBUST=1
FROM node:slim AS base
# Install Python and build tools for native dependencies
# Install Chromium and dependencies for Puppeteer
RUN apt-get update && apt-get install -y \
python3 make g++ \
chromium \
fonts-noto-cjk \
fonts-liberation \
fonts-freefont-ttf \
ca-certificates \
libnss3 \
libatk-bridge2.0-0 \
libdrm2 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libxkbcommon0 \
libasound2 \
libatspi2.0-0 \
libgtk-3-0 \
libglib2.0-0 \
libxss1 \
libgconf-2-4 \
&& rm -rf /var/lib/apt/lists/*
# Set Puppeteer to use installed Chromium
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
# Install dependencies only when needed
FROM base AS deps
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci --include=optional; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Install the correct platform-specific packages based on architecture
RUN if [ "$(uname -m)" = "x86_64" ]; then \
npm install lightningcss-linux-x64-gnu@1.29.1 --no-save; \
elif [ "$(uname -m)" = "aarch64" ]; then \
npm install lightningcss-linux-arm64-gnu@1.29.1 --no-save; \
fi && \
npm rebuild @tailwindcss/oxide --update-binary
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
# Clear all cache to avoid build issues
RUN rm -rf .next node_modules/.cache
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Rebuild native dependencies for the builder stage
# Rebuild sharp and other native modules for the platform
RUN if [ "$(uname -m)" = "x86_64" ]; then \
npm install lightningcss-linux-x64-gnu@1.29.1 --no-save; \
elif [ "$(uname -m)" = "aarch64" ]; then \
npm install lightningcss-linux-arm64-gnu@1.29.1 --no-save; \
fi && \
npm rebuild sharp && \
npm rebuild @tailwindcss/oxide --update-binary
# Clean up build artifacts
RUN rm -rf .next/cache node_modules/.cache
# Build arguments for API keys (passed from HuggingFace Spaces environment)
ARG OPENAI_TEMPLATE_AI_DEV
ARG OPENAI_GENERATE_FV_AI
ARG CLAUDE_TEMPLATE_AI_DEV
ARG ANTHROPIC_API_KEY
ARG GOOGLE_API_KEY
ARG NEXT_PUBLIC_APP_ENV
ARG OKTA_OAUTH2_ISSUER
ARG OKTA_OAUTH2_CLIENT_ID
ARG OKTA_OAUTH2_CLIENT_SECRET
ARG SECRET
# Set environment variables for build time
ENV NEXT_TELEMETRY_DISABLED=1
ENV NEXT_PUBLIC_APP_ENV=$NEXT_PUBLIC_APP_ENV
ENV OPENAI_TEMPLATE_AI_DEV=$OPENAI_TEMPLATE_AI_DEV
ENV OPENAI_GENERATE_FV_AI=$OPENAI_GENERATE_FV_AI
ENV CLAUDE_TEMPLATE_AI_DEV=$CLAUDE_TEMPLATE_AI_DEV
ENV ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY
ENV GOOGLE_API_KEY=$GOOGLE_API_KEY
ENV OKTA_OAUTH2_ISSUER=$OKTA_OAUTH2_ISSUER
ENV OKTA_OAUTH2_CLIENT_ID=$OKTA_OAUTH2_CLIENT_ID
ENV OKTA_OAUTH2_CLIENT_SECRET=$OKTA_OAUTH2_CLIENT_SECRET
ENV SECRET=$SECRET
# Set memory limit for build process
ENV NODE_OPTIONS="--max-old-space-size=2048"
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Remove build cache to reduce image size (keep only necessary runtime files)
RUN rm -rf .next/cache/webpack .next/cache/swc node_modules/.cache
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Disable Next.js telemetry and set cache to writable location
ENV NEXT_TELEMETRY_DISABLED=1
ENV TMPDIR=/tmp
# Runtime environment variables for API keys
ARG OPENAI_TEMPLATE_AI_DEV
ARG OPENAI_GENERATE_FV_AI
ARG CLAUDE_TEMPLATE_AI_DEV
ARG ANTHROPIC_API_KEY
ARG GOOGLE_API_KEY
ARG NEXT_PUBLIC_APP_ENV
ARG OKTA_OAUTH2_ISSUER
ARG OKTA_OAUTH2_CLIENT_ID
ARG OKTA_OAUTH2_CLIENT_SECRET
ARG SECRET
ENV NEXT_PUBLIC_APP_ENV=$NEXT_PUBLIC_APP_ENV
ENV OPENAI_TEMPLATE_AI_DEV=$OPENAI_TEMPLATE_AI_DEV
ENV OPENAI_GENERATE_FV_AI=$OPENAI_GENERATE_FV_AI
ENV CLAUDE_TEMPLATE_AI_DEV=$CLAUDE_TEMPLATE_AI_DEV
ENV ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY
ENV GOOGLE_API_KEY=$GOOGLE_API_KEY
ENV OKTA_OAUTH2_ISSUER=$OKTA_OAUTH2_ISSUER
ENV OKTA_OAUTH2_CLIENT_ID=$OKTA_OAUTH2_CLIENT_ID
ENV OKTA_OAUTH2_CLIENT_SECRET=$OKTA_OAUTH2_CLIENT_SECRET
ENV SECRET=$SECRET
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs --home /home/nextjs
# Copy node_modules for runtime (including Puppeteer)
COPY --from=builder /app/node_modules ./node_modules
RUN chown -R nextjs:nodejs ./node_modules
# Ensure nextjs user has access to home directory
RUN chown -R nextjs:nodejs /home/nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# Copy .next directory but exclude cache to avoid permission issues
COPY --from=builder --chown=nextjs:nodejs /app/.next/server ./.next/server
COPY --from=builder --chown=nextjs:nodejs /app/.next/required-server-files.json ./.next/required-server-files.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/routes-manifest.json ./.next/routes-manifest.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/build-manifest.json ./.next/build-manifest.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/package.json ./.next/package.json
# Copy optional manifest files (may not exist in all builds)
RUN --mount=type=bind,from=builder,source=/app/.next,target=/tmp/source \
if [ -f /tmp/source/prerender-manifest.json ]; then cp /tmp/source/prerender-manifest.json ./.next/; fi && \
if [ -f /tmp/source/react-loadable-manifest.json ]; then cp /tmp/source/react-loadable-manifest.json ./.next/; fi && \
chown -R nextjs:nodejs ./.next/
# Create cache directories and ensure full permissions (combining both approaches)
RUN mkdir -p /tmp/.next/cache/images && \
mkdir -p /app/.next/cache/images && \
chmod -R 777 /tmp && \
chmod -R 755 /app/.next && \
chmod -R 777 /app/.next/cache/images && \
chown -R nextjs:nodejs /tmp/.next && \
chown -R nextjs:nodejs /app/.next
USER nextjs
EXPOSE 7860
ENV PORT=7860
ENV HOSTNAME="0.0.0.0"
# Optimize for HuggingFace free tier
ENV NODE_OPTIONS="--max-old-space-size=1024"
CMD ["node", "server.js"]