fix(docker): bundle socket.io transitive deps into crm-app runner
The crm-app image cherry-copied only socket.io + @socket.io into the runner's node_modules, omitting their transitive closure (engine.io → accepts/ws/cors, ...). server-custom.js is built with esbuild --packages=external, so it require()s those at runtime and crashed with MODULE_NOT_FOUND 'accepts' on first boot. CI reported success because it only builds+pushes — the image runtime was never exercised. Add a hoisted (symlink-free) prod-deps stage and overlay the complete prod dependency tree onto the traced standalone subset. Hoisted layout makes the Docker COPY faithful (pnpm's default symlinked layout dereferences and breaks resolution). Validated locally: accepts, engine.io, socket.io, @socket.io/redis-adapter, ws, cors all resolve. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
26
Dockerfile
26
Dockerfile
@@ -5,6 +5,17 @@ WORKDIR /app
|
|||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
RUN pnpm install --frozen-lockfile --prod=false
|
RUN pnpm install --frozen-lockfile --prod=false
|
||||||
|
|
||||||
|
# Stage 1b: Production dependency tree in a flat (hoisted) node_modules.
|
||||||
|
# Hoisted = symlink-free, so a Docker COPY into the runner is faithful
|
||||||
|
# (copying pnpm's default symlinked layout dereferences and breaks
|
||||||
|
# transitive resolution); complete = the custom socket.io server's deps
|
||||||
|
# (engine.io, accepts, ws, ...) all resolve at runtime.
|
||||||
|
FROM node:20-alpine AS prod-deps
|
||||||
|
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
RUN echo "node-linker=hoisted" > .npmrc && pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
# Stage 2: Build the application
|
# Stage 2: Build the application
|
||||||
FROM node:20-alpine AS builder
|
FROM node:20-alpine AS builder
|
||||||
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
|
RUN corepack enable && corepack prepare pnpm@10.33.2 --activate
|
||||||
@@ -30,12 +41,15 @@ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/dist/server.js ./server-custom.js
|
COPY --from=builder --chown=nextjs:nodejs /app/dist/server.js ./server-custom.js
|
||||||
# Pin socket.io + @socket.io/redis-adapter into the runner — the custom
|
# The custom socket.io server (server-custom.js, built with esbuild
|
||||||
# server (server-custom.js) requires them at runtime, but the Next
|
# --packages=external) resolves socket.io and its FULL transitive closure
|
||||||
# tracer has no reason to include them in .next/standalone since no
|
# (engine.io → accepts/ws/cors, @socket.io/redis-adapter, ...) from
|
||||||
# Next route imports the socket server. (build-auditor C3)
|
# node_modules at runtime. The Next tracer omits these from
|
||||||
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/socket.io ./node_modules/socket.io
|
# .next/standalone because no Next route imports the socket server, and
|
||||||
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/@socket.io ./node_modules/@socket.io
|
# cherry-copying just socket.io/ leaves its deps unresolved
|
||||||
|
# (MODULE_NOT_FOUND 'accepts'). Overlay the complete prod dependency tree
|
||||||
|
# (flat/hoisted layout → symlink-safe copy) on top of the traced subset.
|
||||||
|
COPY --from=prod-deps --chown=nextjs:nodejs /app/node_modules ./node_modules
|
||||||
USER nextjs
|
USER nextjs
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
||||||
|
|||||||
Reference in New Issue
Block a user