fix(ci): hoisted node_modules + alpine binary target for Prisma in Docker
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m45s

Root cause (from build log):
1. Prisma 6 generates client into @prisma/client package dir (not .prisma/client)
2. pnpm default isolated linker puts everything in .pnpm/ store with symlinks
   at top-level — Docker COPY of @prisma followed broken/incomplete symlinks
3. node:22-alpine needs linux-musl-openssl-3.0.x engine binary

Fixes:
- .npmrc: node-linker=hoisted → flat node_modules, COPY behaves like npm
- schema.prisma: add linux-musl-openssl-3.0.x to binaryTargets
- Dockerfile: drop dead .prisma/client checks, copy only @prisma (where
  Prisma 6 actually writes the client) plus standalone output

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
zyc 2026-05-13 14:13:37 +08:00
parent 409c4c4b50
commit 7506372abd
3 changed files with 18 additions and 10 deletions

3
.npmrc Normal file
View File

@ -0,0 +1,3 @@
# 让 pnpm 用扁平 node_modules避免 .pnpm/ 软链结构导致 Docker COPY 断裂
node-linker=hoisted
auto-install-peers=true

View File

@ -7,14 +7,16 @@ WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate \
&& pnpm config set registry https://registry.npmmirror.com
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
# .npmrc 必须先 COPY否则 pnpm install 看不到 node-linker=hoisted
COPY .npmrc package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY prisma ./prisma
# pnpm 10+ 在 root/CI 环境默认不跑 lifecycle scripts因此显式调用 prisma generate
# pnpm 10+ 在 root/CI 默认跳过 lifecycle scripts因此显式调用 prisma generate
# Prisma 6 直接把 client 写入 @prisma/client 包目录(不再用 .prisma/client
RUN pnpm install --frozen-lockfile --ignore-scripts \
&& pnpm exec prisma generate \
&& ls -la /app/node_modules/.prisma/client/ \
&& ls -la /app/node_modules/@prisma/client/
&& ls -la /app/node_modules/@prisma/client/ \
&& ls /app/node_modules/@prisma/client/ | grep -E "(libquery_engine|schema.prisma|index.js)" || true
# ───────────── 2. builderNext.js 构建standalone 产物) ─────────────
FROM node:22-alpine AS builder
@ -27,10 +29,11 @@ COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
# 再次保险生成COPY . . 会覆盖 prisma/ schema 的最新版本),然后构建
# COPY . . 会覆盖 prisma/schema 的最新版本,需要再 generate 一次确保 client 同步
RUN pnpm exec prisma generate \
&& pnpm exec next build \
&& ls -la /app/node_modules/.prisma/client/
&& ls -la /app/node_modules/@prisma/client/ \
&& ls -la /app/.next/standalone/
# ───────────── 3. runner最小运行时镜像 ─────────────
FROM node:22-alpine AS runner
@ -45,13 +48,12 @@ ENV HOSTNAME=0.0.0.0
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs
# Next.js standalone 输出 + 静态资源 + public
# Next.js standalone 自带通过 tracing 解析出的运行时依赖(含 @prisma/client
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
# Prisma生成的 client + schema运行时 db:push / 迁移可能用到)
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.prisma ./node_modules/.prisma
# 显式补 Prismatracing 有时会漏掉 engine 二进制和 schema
COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma

View File

@ -4,7 +4,10 @@
// =============================================================
generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
// native本地开发macOS / linux-glibc
// linux-musl-openssl-3.0.x容器运行时node:22-alpine
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {