Fix backend image build: use hoisted node_modules in the Docker context
CI / test (push) Successful in 24s
CI / lint (push) Successful in 27s
CI / secrets-scan (push) Successful in 5s
CI / vuln-scan (push) Successful in 12s
CI / sast (push) Successful in 10s
CI / build-images (push) Successful in 2m20s
CI / image-scan (push) Failing after 44s
CI / push (push) Has been skipped
CI / test (push) Successful in 24s
CI / lint (push) Successful in 27s
CI / secrets-scan (push) Successful in 5s
CI / vuln-scan (push) Successful in 12s
CI / sast (push) Successful in 10s
CI / build-images (push) Successful in 2m20s
CI / image-scan (push) Failing after 44s
CI / push (push) Has been skipped
The previous Dockerfile assumed Prisma's generated client landed at
tehriehlbudget-backend/node_modules/.prisma/client/, but pnpm's default
isolated layout writes it inside node_modules/.pnpm/@prisma+client@.../
node_modules/, which doesn't survive a multi-stage COPY. The build
failed at the runtime stage trying to copy a path that didn't exist.
Switch the image to hoisted (flat) node_modules via a build-context-only
.npmrc so prisma generate writes to predictable /repo/node_modules/
{@prisma,.prisma}/ paths. Local dev keeps the isolated layout — the
.npmrc lives only inside the docker build context, not on disk.
The runtime stage now copies node_modules from the workspace root
(where hoisted deps live), then overlays the generated Prisma client
from the build stage (since the prod-deps stage strips the prisma CLI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,13 @@ FROM node:${NODE_VERSION}-alpine AS deps
|
||||
RUN apk add --no-cache libc6-compat openssl
|
||||
RUN corepack enable && corepack prepare pnpm@9 --activate
|
||||
WORKDIR /repo
|
||||
# Force a hoisted (flat) node_modules layout for the image. The default pnpm
|
||||
# isolated layout puts dependencies inside node_modules/.pnpm/<pkg>@<ver>/
|
||||
# which makes `prisma generate`'s output (node_modules/.prisma/client/) live
|
||||
# in a path that doesn't survive a multi-stage COPY. Hoisted gives us
|
||||
# predictable /repo/node_modules/{@prisma,.prisma}/ paths. Local dev is
|
||||
# unaffected — this .npmrc only exists inside the build context.
|
||||
RUN echo "node-linker=hoisted" > /repo/.npmrc
|
||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./
|
||||
COPY tehriehlbudget-backend/package.json tehriehlbudget-backend/
|
||||
COPY tehriehlbudget-frontend/package.json tehriehlbudget-frontend/
|
||||
@@ -30,11 +37,12 @@ ENV NODE_ENV=production
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/dist ./dist
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/prisma ./prisma
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/package.json ./package.json
|
||||
COPY --from=prod-deps --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/node_modules ./node_modules
|
||||
# Overlay generated Prisma client from the build stage (the prod-deps stage
|
||||
# pruned the `prisma` CLI devDep, which removes the client during install).
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/tehriehlbudget-backend/node_modules/@prisma ./node_modules/@prisma
|
||||
# With hoisted linker, all deps live at the workspace-root node_modules.
|
||||
COPY --from=prod-deps --chown=nodeapp:nodeapp /repo/node_modules ./node_modules
|
||||
# Overlay the generated Prisma client from the build stage. The prod-deps
|
||||
# stage doesn't have the `prisma` CLI (devDep) so it can't generate.
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=build --chown=nodeapp:nodeapp /repo/node_modules/@prisma ./node_modules/@prisma
|
||||
USER nodeapp
|
||||
EXPOSE 3000
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
|
||||
Reference in New Issue
Block a user