Copy the plugin staging script into the build that needs it

`npm run build` fires a `prebuild` hook that runs
`node ../scripts/stage-frontend.mjs`, the script that copies each plugin's
frontend into the Vite tree and codegens routes.gen.js. The Dockerfile's
frontend stage copied `frontend/` alone and flattened it to the stage root, so
`../scripts` resolved to `/scripts`, which does not exist. Every image build
since the staging script landed has died there on `Cannot find module`.

The stage now keeps the repo-relative layout - frontend/, scripts/ and plugins/
as siblings under /build - because the script resolves its repo root as its own
directory's parent. The final stage copies from /build/frontend/dist to match.

Verified with a real build, not by inspection: 16 plugin frontends staged, vite
produced dist, and the finished image carries frontend/dist with 241 assets.

This also unblocks SITE_PLUGINS lean image builds, which until now only
scripts/build-site.sh could do.
This commit is contained in:
cproudlock
2026-08-19 19:22:20 -04:00
parent 3f7cc37b00
commit 375dd3fb9d

View File

@@ -24,12 +24,22 @@ FROM node:20-slim AS frontendbuild
WORKDIR /build WORKDIR /build
# Copy only the manifests first so `npm ci` caches on dependency changes. # Copy only the manifests first so `npm ci` caches on dependency changes.
COPY frontend/package*.json ./ COPY frontend/package*.json ./frontend/
RUN npm ci RUN cd frontend && npm ci
COPY frontend/ ./ # The frontend keeps its repo-relative layout here, because npm prebuild runs
RUN npm run build # `node ../scripts/stage-frontend.mjs`, which stages each plugin's frontend/ into
# Output lands in /build/dist (Vite default), copied into the final stage below. # the Vite tree and codegens routes.gen.js. That script resolves its repo root as
# its own directory's parent, so it needs scripts/ and plugins/ as SIBLINGS of
# frontend/. Building with frontend/ flattened to the stage root made `../scripts`
# resolve to /scripts and the build failed on a missing module.
COPY scripts/stage-frontend.mjs ./scripts/
COPY plugins/ ./plugins/
COPY frontend/ ./frontend/
RUN cd frontend && npm run build
# Output lands in /build/frontend/dist (Vite default), copied into the final
# stage below.
# ---- Stage 2: Python application image ---- # ---- Stage 2: Python application image ----
FROM python:3.14-slim AS base FROM python:3.14-slim AS base
@@ -60,7 +70,7 @@ COPY scripts/ ./scripts/
COPY wsgi.py ./ COPY wsgi.py ./
# Built SPA from stage 1. Flask serves it via register_frontend_routes. # Built SPA from stage 1. Flask serves it via register_frontend_routes.
COPY --from=frontendbuild /build/dist ./frontend/dist COPY --from=frontendbuild /build/frontend/dist ./frontend/dist
RUN useradd --create-home --shell /bin/bash shopdb \ RUN useradd --create-home --shell /bin/bash shopdb \
&& chown -R shopdb:shopdb /app && chown -R shopdb:shopdb /app