Two runtime-surface fixes surfacing from the optical-dev deploy.
1) Seed's `postgres-array/index.js` kept missing even after --no-cache
rebuilds. Root cause: the Next.js standalone output traces package
manifests aggressively but sometimes leaves the `main` file body
out when the package isn't reachable from the app's import graph
(postgres-array is a transitive of pg, only reached via the seed
script, not the app runtime). Our `npm install --no-save
@prisma/adapter-pg` at build time then saw the partial install and
short-circuited. Runtime tsx resolution then blew up on `require
postgres-array`.
Fixed two ways, layered:
a) In the builder stage, after `npm run build`, esbuild the seed
into a self-contained CJS bundle at prisma/seed-dow.cjs.
`--packages=external` keeps npm packages as runtime require()s
so native .node files (via @prisma/client) work, but everything
else is bundled so the seed no longer depends on runtime module
resolution in the fragile standalone tree.
b) In the runner stage, `npm install --no-save --force` (plus
explicit `pg@8` which pulls its postgres-* deps cleanly)
overwrites any partial packages the standalone shipped with.
Belt-and-braces with the bundled seed.
c) package.json `db:seed` now prefers `node prisma/seed-dow.cjs`
and falls back to `tsx prisma/seed-dow.ts` if the .cjs isn't
there (e.g. when running the seed from a dev box where no build
happened). Both paths produce identical output.
No more runtime tsx install — dropped `npm install -g tsx@4` from
the runner image. That was always a workaround; the bundle is the
actual fix.
2) Sidebar logo not rendering — Next.js's `<Image>` with basePath +
the standalone image optimizer is finicky; the image file IS at
/app/public/navbar-logo.png in the container but Next's
`/_next/image?url=...` pipeline was returning 404 for it. Swapped
to a plain `<img>` (with the eslint-disable comment so the rule
doesn't whine). The file is ~4KB, image optimization added
nothing. Desktop + mobile sidebars both use the plain tag now.
Verified: tsc --noEmit ✓ zero errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
91 lines
3.1 KiB
Docker
91 lines
3.1 KiB
Docker
FROM node:22-alpine AS base
|
|
|
|
# FFmpeg for video transcoding (HLS), thumbnail extraction, and metadata
|
|
RUN apk add --no-cache ffmpeg
|
|
|
|
# Install dependencies only when needed
|
|
FROM base AS deps
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json* ./
|
|
RUN npm ci --ignore-scripts
|
|
RUN npx prisma generate || true
|
|
|
|
# Rebuild source code only when needed
|
|
FROM base AS builder
|
|
WORKDIR /app
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
COPY . .
|
|
|
|
# Generate Prisma client
|
|
RUN npx prisma generate
|
|
|
|
# Build the Next.js app
|
|
RUN npm run build
|
|
|
|
# Pre-compile the seed to a self-contained CJS bundle. Runtime then runs
|
|
# plain `node prisma/seed-dow.cjs` and avoids the whole tsx+module-resolution
|
|
# nightmare: Next.js's standalone node_modules was aggressively reshuffling
|
|
# the tree after install, leaving packages like postgres-array with a
|
|
# manifest but no index.js. Bundling sidesteps that entirely.
|
|
#
|
|
# `--packages=external` keeps NPM packages (e.g. bcryptjs, @prisma/*) as
|
|
# runtime require() calls so the bundle stays small and native .node files
|
|
# in @prisma/client work normally.
|
|
RUN npx -y esbuild@0.24 prisma/seed-dow.ts \
|
|
--bundle --platform=node --format=cjs --target=node22 \
|
|
--outfile=prisma/seed-dow.cjs \
|
|
--packages=external
|
|
|
|
# Production image
|
|
FROM base AS runner
|
|
WORKDIR /app
|
|
|
|
ENV NODE_ENV=production
|
|
|
|
RUN addgroup --system --gid 1001 nodejs
|
|
RUN adduser --system --uid 1001 nextjs
|
|
|
|
COPY --from=builder /app/public ./public
|
|
|
|
# Copy Next.js standalone output
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
|
|
# Copy Prisma schema, config, and migrations for runtime
|
|
COPY --from=builder /app/prisma ./prisma
|
|
COPY --from=builder /app/prisma.config.ts ./prisma.config.ts
|
|
COPY --from=builder /app/src/generated ./src/generated
|
|
|
|
# Runtime deps — the Next.js standalone bundle covers the app itself;
|
|
# these extras are for:
|
|
# prisma — migrate-deploy CLI (run at container start)
|
|
# dotenv — prisma.config.ts imports dotenv/config
|
|
# @prisma/adapter-pg — the driver the compiled seed.cjs require()s
|
|
# bcryptjs — the compiled seed.cjs hashes the admin temp pw
|
|
# pg — pulls in postgres-array/bytea/date/interval
|
|
# which Next.js's trace sometimes partially includes
|
|
# (package.json but no index.js) and then npm's
|
|
# "already installed" short-circuit skips
|
|
#
|
|
# --force makes npm overwrite any partial installs the standalone tree
|
|
# shipped with, which is the actual root-cause fix for the recurring
|
|
# "Cannot find module postgres-array/index.js" crash.
|
|
RUN npm install --no-save --force \
|
|
prisma@7.4.2 \
|
|
dotenv@17.3.1 \
|
|
@prisma/adapter-pg@7.4.2 \
|
|
pg@8 \
|
|
bcryptjs@3
|
|
|
|
# Create uploads directories for media storage
|
|
RUN mkdir -p /data/uploads && chown nextjs:nodejs /data/uploads
|
|
RUN mkdir -p /app/public/uploads/revisions && chown -R nextjs:nodejs /app/public/uploads
|
|
|
|
USER nextjs
|
|
|
|
EXPOSE 3000
|
|
|
|
ENV PORT=3000
|
|
ENV HOSTNAME="0.0.0.0"
|
|
|
|
CMD ["sh", "-c", "./node_modules/.bin/prisma migrate deploy && node server.js"]
|