# Single image for the whole monorepo. Each Railway service runs the
# same image with a different start command. Locally:
# `docker compose up --build` runs all three via compose.yaml.
#
# No build step for JS. webjs serves .ts directly via Node's built-in
# `module.stripTypeScriptTypes` (position-preserving whitespace
# replacement, no sourcemap shipped to the browser).
#
# **Node 24+ is REQUIRED** for that path. On Node 22, the runtime falls
# back to esbuild for every .ts file. esbuild's class-declaration
# transformation has been observed to break webjs's SSR walker for
# multi-class component files: Tier-2 components (dialog, tooltip,
# dropdown-menu, etc.) all rendered with the wrong shell because the
# first class's render() was being invoked for every sub-tag. Pinning
# Node 24 here pairs with the AGENTS.md "Node 24+ required" invariant.
#
# Tailwind CSS IS built at image time (CLI, no browser runtime). The
# blog runs `prisma generate` at build and `prisma migrate deploy` at
# start.
FROM node:26-alpine

# openssl is required by Prisma's query engine at runtime.
RUN apk add --no-cache openssl ca-certificates

WORKDIR /app

# --- 1. Install deps (layer cached on manifest changes only) ------------
# Copy every workspace manifest before source so dep changes don't bust
# the source layer and vice versa.
COPY package.json package-lock.json ./
COPY packages/cli/package.json                       ./packages/cli/
COPY packages/core/package.json                      ./packages/core/
COPY packages/mcp/package.json                       ./packages/mcp/
COPY packages/server/package.json                    ./packages/server/
COPY packages/editors/intellisense/package.json         ./packages/editors/intellisense/
COPY packages/ui/package.json                        ./packages/ui/
COPY packages/ui/packages/registry/package.json      ./packages/ui/packages/registry/
COPY packages/ui/packages/website/package.json       ./packages/ui/packages/website/
COPY examples/blog/package.json                      ./examples/blog/
COPY website/package.json                            ./website/
COPY docs/package.json                               ./docs/

# Copy the CLI's bin/ before install so npm can symlink it into
# /app/node_modules/.bin/webjs. Without this, the bin target doesn't
# exist at install time and npm silently skips the symlink - then
# `npm start` inside any workspace fails with `sh: webjs: not found`.
COPY packages/cli/bin                     ./packages/cli/bin

RUN npm install --no-audit --no-fund

# --- 2. Copy source -----------------------------------------------------
COPY packages  ./packages
COPY examples  ./examples
COPY website   ./website
COPY docs      ./docs
# scripts/build-framework-dist.js is invoked by the step-3
# `npm run build:dist --workspace=@webjsdev/core` line, so the
# scripts tree has to be in the image before that step runs.
COPY scripts   ./scripts
# website/app/changelog/page.ts reads ../../../changelog/<pkg>/*.md at
# SSR time. Without copying the changelog tree into the image, the
# deployed page renders "No entries yet."
COPY changelog ./changelog
# website/app/blog/[slug]/page.ts reads ../../../../blog/<slug>.md at
# SSR time (via modules/blog/queries/list-posts.server.ts). Same
# reason as changelog: without the tree in the image, /blog renders
# "No posts yet."
COPY blog ./blog

# --- 3. Build-time work --------------------------------------------------
# Core: build the dist/ bundles. The package.json `prepare` hook is a
# self-guarded no-op during step 1 (manifests-only npm install, before
# scripts/ and packages/core/src/ are copied in), so the bundle has to
# be built explicitly here, after sources land. Without this step,
# production images serve per-file from src/ via the workspace-dev
# fallback, which is functional but waterfalls the browser through ~15
# requests per page instead of one chunk per subpath.
RUN npm run build:dist --workspace=@webjsdev/core

# Blog: generate Prisma client (needs schema.prisma in context).
RUN cd examples/blog && npx prisma generate

# UI registry: no build step. The ui-website composes registry JSON on
# demand from packages/ui/packages/registry/ sources via its route handlers
# (see packages/ui/packages/website/app/_lib/registry.server.ts).

# Tailwind: compile per-app CSS (all four use the CLI, no browser runtime).
# Each compose service's command invokes `webjs.js start` directly, which
# bypasses the per-package `prestart: css:build` hook in npm; the CSS has
# to be ready in the image. Keep this list in sync with the apps that
# have a public/input.css and a `css:build` script in their package.json.
RUN npx tailwindcss -i website/public/input.css                       -o website/public/tailwind.css                       --minify \
 && npx tailwindcss -i docs/public/input.css                          -o docs/public/tailwind.css                          --minify \
 && npx tailwindcss -i examples/blog/public/input.css                 -o examples/blog/public/tailwind.css                 --minify \
 && npx tailwindcss -i packages/ui/packages/website/public/input.css  -o packages/ui/packages/website/public/tailwind.css  --minify

# Default env vars. Railway / compose set their own per service.
ENV NODE_ENV=production

# Platform-neutral readiness gate (mirrors packages/cli/templates/Dockerfile,
# the pattern the scaffold ships to users). webjs answers /__webjs/ready with
# 503 until the instance is fully warm (analysis + first vendor attempt), then
# 200. This image-level HEALTHCHECK is honoured by Docker, compose, and most
# Docker-based platforms, so the readiness gate works the same everywhere
# without a per-platform file. Each service sets its own PORT (compose env, or
# Railway injects it); the probe reads it, defaulting to 8080. Dependency-free
# (Node's built-in fetch, no curl/wget). Platforms that read their own config
# point the equivalent knob at the same path (Railway healthcheckPath in
# railway.json, Fly [checks], k8s readinessProbe).
HEALTHCHECK --interval=15s --timeout=3s --start-period=40s --retries=5 \
  CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||8080)+'/__webjs/ready').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"]

CMD ["node", "--help"]
