Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
node_modules
**/node_modules
**/.next
**/.turbo
**/.env
**/.env.*
**/coverage
**/*.log
.git
.next
.env
91 changes: 73 additions & 18 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,28 +1,83 @@
# ---- build stage ----
FROM node:20-alpine AS builder
# syntax=docker/dockerfile:1.7

FROM node:20-alpine AS base

WORKDIR /repo
RUN corepack enable

# 1) install workspace deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml turbo.json tsconfig.json ./
COPY apps ./apps
ENV COREPACK_ENABLE=0 \
PNPM_HOME=/pnpm \
PATH=/pnpm:$PATH

# Keep the package manager in a shared base layer. Source-code changes never
# invalidate this layer.
RUN npm install --global pnpm@9.0.0


FROM base AS dependencies

# Install only after copying workspace manifests. The layer is rebuilt only
# when a dependency or workspace definition changes.
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/game_craft/package.json ./apps/game_craft/package.json
COPY apps/level_up/package.json ./apps/level_up/package.json
COPY apps/ssc/package.json ./apps/ssc/package.json
COPY packages/core/package.json ./packages/core/package.json
COPY packages/tailwind-config/package.json ./packages/tailwind-config/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/utils/package.json ./packages/utils/package.json

RUN --mount=type=cache,id=frontend-pnpm-store,target=/pnpm/store,sharing=locked \
pnpm config set store-dir /pnpm/store && \
pnpm config set package-import-method copy && \
pnpm install --frozen-lockfile


FROM dependencies AS builder

# Defaults keep a direct `docker build em_frontend` useful. Compose overrides
# these values for the other applications.
ARG APP_PATH=apps/ssc
ARG APP_FILTER=@ssc/web
ARG GAME_CRAFT_SSC_EVENT_ID

COPY turbo.json tsconfig.json ./
COPY packages ./packages
RUN pnpm install --frozen-lockfile
COPY ${APP_PATH} ./${APP_PATH}

# The trailing ellipsis tells Turbo to build the selected app and only its
# workspace dependencies, instead of rebuilding all frontend applications.
RUN --mount=type=cache,id=frontend-turbo,target=/repo/.turbo \
--mount=type=cache,id=frontend-next-ssc,target=/repo/apps/ssc/.next/cache,sharing=locked \
--mount=type=cache,id=frontend-next-level-up,target=/repo/apps/level_up/.next/cache,sharing=locked \
--mount=type=cache,id=frontend-next-game-craft,target=/repo/apps/game_craft/.next/cache,sharing=locked \
if { [ "$APP_PATH" = "apps/level_up" ] || [ "$APP_PATH" = "apps/game_craft" ]; } && \
! echo "$GAME_CRAFT_SSC_EVENT_ID" | grep -Eq '^[1-9][0-9]*$'; then \
echo "GAME_CRAFT_SSC_EVENT_ID must be a positive integer for $APP_PATH" >&2; \
exit 1; \
fi && \
pnpm turbo run build --filter="${APP_FILTER}..."

# 2) build the Next.js site
RUN pnpm build

# ---- run stage ----
FROM node:20-alpine
FROM node:20-alpine AS runner

ARG APP_PATH=apps/ssc

ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
HOSTNAME=0.0.0.0 \
PORT=3000

WORKDIR /app
ENV NODE_ENV=production

# 1) Enable Corepack and turn the stub into a real pnpm install
RUN corepack enable && corepack prepare pnpm@8 --activate
# The standalone directory contains only the traced production server and its
# runtime dependencies. Static and public assets are intentionally separate.
COPY --from=builder --chown=node:node /repo/${APP_PATH}/.next/standalone ./
COPY --from=builder --chown=node:node /repo/${APP_PATH}/.next/static ./${APP_PATH}/.next/static
COPY --from=builder --chown=node:node /repo/${APP_PATH}/public ./${APP_PATH}/public

# 2) Copy the build output (+ node_modules tree) produced in the builder stage
COPY --from=builder /repo .
USER node
WORKDIR /app/${APP_PATH}

# 3) Start only the Next.js app (CMD is overridden in docker compose)
EXPOSE 3000
CMD ["pnpm", "-F", "web", "start"]

CMD ["node", "server.js"]
56 changes: 35 additions & 21 deletions apps/game_craft/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
# Step 1: Use a lightweight Node.js base
FROM node:20-alpine AS base

# Step 2: Set working directory
WORKDIR /app
# syntax=docker/dockerfile:1.7

# Step 3: Copy only dependency files first (for caching)
COPY pnpm-lock.yaml ./
COPY package.json ./
COPY pnpm-workspace.yaml ./
COPY apps/game_craft/package.json apps/game_craft/
COPY packages/core/package.json packages/core/
COPY packages/ui/package.json packages/ui/

# Step 4: Install deps with pnpm (monorepo-aware)
RUN npm install -g pnpm@9 && pnpm install --frozen-lockfile
# Direct-build entry point. Use the em_frontend directory as build context.
FROM node:20-alpine AS base
WORKDIR /repo
ENV COREPACK_ENABLE=0 PNPM_HOME=/pnpm PATH=/pnpm:$PATH
RUN npm install --global pnpm@9.0.0

# Step 5: Copy all source code
COPY . .
FROM base AS dependencies
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/game_craft/package.json ./apps/game_craft/package.json
COPY apps/level_up/package.json ./apps/level_up/package.json
COPY apps/ssc/package.json ./apps/ssc/package.json
COPY packages/core/package.json ./packages/core/package.json
COPY packages/tailwind-config/package.json ./packages/tailwind-config/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/utils/package.json ./packages/utils/package.json
RUN --mount=type=cache,id=frontend-pnpm-store,target=/pnpm/store,sharing=locked \
pnpm config set store-dir /pnpm/store && \
pnpm config set package-import-method copy && \
pnpm install --frozen-lockfile

# Step 6: Build game_craft
RUN pnpm run build
FROM dependencies AS builder
COPY turbo.json tsconfig.json ./
COPY packages ./packages
COPY apps/game_craft ./apps/game_craft
RUN --mount=type=cache,id=frontend-turbo,target=/repo/.turbo \
--mount=type=cache,id=frontend-next-game-craft,target=/repo/apps/game_craft/.next/cache,sharing=locked \
pnpm turbo run build --filter="@ssc/game_craft..."

# Step 7: Start production server
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0 PORT=3000
COPY --from=builder --chown=node:node /repo/apps/game_craft/.next/standalone ./
COPY --from=builder --chown=node:node /repo/apps/game_craft/.next/static ./apps/game_craft/.next/static
COPY --from=builder --chown=node:node /repo/apps/game_craft/public ./apps/game_craft/public
USER node
WORKDIR /app/apps/game_craft
EXPOSE 3000
CMD ["pnpm", "start"]
CMD ["node", "server.js"]
3 changes: 3 additions & 0 deletions apps/game_craft/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import createNextIntlPlugin from "next-intl/plugin";
import type { NextConfig } from "next";
import path from "node:path";

const withNextIntl = createNextIntlPlugin("./lib/i18n.ts");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});

const nextConfig: NextConfig = {
output: "standalone",
outputFileTracingRoot: path.join(__dirname, "../.."),
env: {
GAME_CRAFT_SSC_EVENT_ID: process.env.GAME_CRAFT_SSC_EVENT_ID,
},
Expand Down
56 changes: 35 additions & 21 deletions apps/level_up/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
# Step 1: Use a lightweight Node.js base
FROM node:20-alpine AS base

# Step 2: Set working directory
WORKDIR /app
# syntax=docker/dockerfile:1.7

# Step 3: Copy only dependency files first (for caching)
COPY pnpm-lock.yaml ./
COPY package.json ./
COPY pnpm-workspace.yaml ./
COPY apps/game_craft/package.json apps/game_craft/
COPY packages/core/package.json packages/core/
COPY packages/ui/package.json packages/ui/

# Step 4: Install deps with pnpm (monorepo-aware)
RUN npm install -g pnpm@9 && pnpm install --frozen-lockfile
# Direct-build entry point. Use the em_frontend directory as build context.
FROM node:20-alpine AS base
WORKDIR /repo
ENV COREPACK_ENABLE=0 PNPM_HOME=/pnpm PATH=/pnpm:$PATH
RUN npm install --global pnpm@9.0.0

# Step 5: Copy all source code
COPY . .
FROM base AS dependencies
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/game_craft/package.json ./apps/game_craft/package.json
COPY apps/level_up/package.json ./apps/level_up/package.json
COPY apps/ssc/package.json ./apps/ssc/package.json
COPY packages/core/package.json ./packages/core/package.json
COPY packages/tailwind-config/package.json ./packages/tailwind-config/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/utils/package.json ./packages/utils/package.json
RUN --mount=type=cache,id=frontend-pnpm-store,target=/pnpm/store,sharing=locked \
pnpm config set store-dir /pnpm/store && \
pnpm config set package-import-method copy && \
pnpm install --frozen-lockfile

# Step 6: Build game_craft
RUN pnpm run build
FROM dependencies AS builder
COPY turbo.json tsconfig.json ./
COPY packages ./packages
COPY apps/level_up ./apps/level_up
RUN --mount=type=cache,id=frontend-turbo,target=/repo/.turbo \
--mount=type=cache,id=frontend-next-level-up,target=/repo/apps/level_up/.next/cache,sharing=locked \
pnpm turbo run build --filter="@ssc/level_up..."

# Step 7: Start production server
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0 PORT=3000
COPY --from=builder --chown=node:node /repo/apps/level_up/.next/standalone ./
COPY --from=builder --chown=node:node /repo/apps/level_up/.next/static ./apps/level_up/.next/static
COPY --from=builder --chown=node:node /repo/apps/level_up/public ./apps/level_up/public
USER node
WORKDIR /app/apps/level_up
EXPOSE 3000
CMD ["pnpm", "start"]
CMD ["node", "server.js"]
3 changes: 3 additions & 0 deletions apps/level_up/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import createNextIntlPlugin from "next-intl/plugin";
import type { NextConfig } from "next";
import path from "node:path";

const withNextIntl = createNextIntlPlugin("./lib/i18n.ts");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});

const nextConfig: NextConfig = {
output: "standalone",
outputFileTracingRoot: path.join(__dirname, "../.."),
env: {
GAME_CRAFT_SSC_EVENT_ID: process.env.GAME_CRAFT_SSC_EVENT_ID,
},
Expand Down
59 changes: 35 additions & 24 deletions apps/ssc/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
# Step 1: Base image
FROM node:20-alpine AS base

# Step 2: Working directory
WORKDIR /app
# syntax=docker/dockerfile:1.7

# Step 3: Copy dependency files first
COPY pnpm-lock.yaml ./
COPY package.json ./
COPY pnpm-workspace.yaml ./
COPY apps/ssc/package.json apps/ssc/
COPY packages/core/package.json packages/core/
COPY packages/ui/package.json packages/ui/
# Direct-build entry point. Use the em_frontend directory as build context.
FROM node:20-alpine AS base
WORKDIR /repo
ENV COREPACK_ENABLE=0 PNPM_HOME=/pnpm PATH=/pnpm:$PATH
RUN npm install --global pnpm@9.0.0

# Step 4: Install dependencies
RUN npm install -g pnpm@9 && pnpm install --frozen-lockfile
FROM base AS dependencies
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY apps/game_craft/package.json ./apps/game_craft/package.json
COPY apps/level_up/package.json ./apps/level_up/package.json
COPY apps/ssc/package.json ./apps/ssc/package.json
COPY packages/core/package.json ./packages/core/package.json
COPY packages/tailwind-config/package.json ./packages/tailwind-config/package.json
COPY packages/ui/package.json ./packages/ui/package.json
COPY packages/utils/package.json ./packages/utils/package.json
RUN --mount=type=cache,id=frontend-pnpm-store,target=/pnpm/store,sharing=locked \
pnpm config set store-dir /pnpm/store && \
pnpm config set package-import-method copy && \
pnpm install --frozen-lockfile

# Step 5: Copy source code
COPY . .
FROM dependencies AS builder
COPY turbo.json tsconfig.json ./
COPY packages ./packages
COPY apps/ssc ./apps/ssc
RUN --mount=type=cache,id=frontend-turbo,target=/repo/.turbo \
--mount=type=cache,id=frontend-next-ssc,target=/repo/apps/ssc/.next/cache,sharing=locked \
pnpm turbo run build --filter="@ssc/web..."

# Step 6: Build ssc app
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 HOSTNAME=0.0.0.0 PORT=3000
COPY --from=builder --chown=node:node /repo/apps/ssc/.next/standalone ./
COPY --from=builder --chown=node:node /repo/apps/ssc/.next/static ./apps/ssc/.next/static
COPY --from=builder --chown=node:node /repo/apps/ssc/public ./apps/ssc/public
USER node
WORKDIR /app/apps/ssc
RUN pnpm run build

# Step 7: Expose port (choose 3001 for ssc)
EXPOSE 3001

# Step 8: Start app
CMD ["pnpm", "start"]
EXPOSE 3000
CMD ["node", "server.js"]
3 changes: 3 additions & 0 deletions apps/ssc/next.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { NextConfig } from "next";
import path from "node:path";

const nextConfig: NextConfig = {
output: "standalone",
outputFileTracingRoot: path.join(__dirname, "../.."),
// turbopack: {
// resolveAlias: {
// "~": __dirname,
Expand Down
Loading