collin/mahjong
67a30800c94a7a04ea0b7a37233d6afa3a6fae2c / Dockerfile
| 1 | # The whole production stack is one process: the built game out of dist/, and |
| 2 | # the room relay on /ws of the same origin. So the image is a node runtime, the |
| 3 | # bundle, and `server/`. |
| 4 | # |
| 5 | # No state. Rooms live in memory, and a restart drops them — the next visitor |
| 6 | # on an old link recreates the room empty and a host mid-game republishes its |
| 7 | # table on the next move. There is nothing here to mount a volume for. |
| 8 | |
| 9 | # ---- build: typecheck, bundle ------------------------------------------ |
| 10 | FROM node:24-alpine AS builder |
| 11 | WORKDIR /app |
| 12 | |
| 13 | COPY package.json package-lock.json ./ |
| 14 | RUN npm ci |
| 15 | |
| 16 | COPY . . |
| 17 | RUN npm run build |
| 18 | |
| 19 | # The runtime needs `ws` and nothing else the dev toolchain drags in. |
| 20 | RUN npm prune --omit=dev |
| 21 | |
| 22 | # ---- runtime ------------------------------------------------------------ |
| 23 | FROM node:24-alpine AS runtime |
| 24 | WORKDIR /app |
| 25 | |
| 26 | RUN addgroup -S app && adduser -S app -G app |
| 27 | |
| 28 | COPY --from=builder --chown=app:app /app/node_modules ./node_modules |
| 29 | COPY --from=builder --chown=app:app /app/dist ./dist |
| 30 | COPY --from=builder --chown=app:app /app/server ./server |
| 31 | COPY --from=builder --chown=app:app /app/package.json ./package.json |
| 32 | |
| 33 | ENV NODE_ENV=production |
| 34 | ENV HOST=0.0.0.0 |
| 35 | ENV PORT=3000 |
| 36 | |
| 37 | EXPOSE 3000 |
| 38 | USER app |
| 39 | |
| 40 | # server/ is TypeScript and node strips the types itself — there is no build |
| 41 | # step for it and nothing generated to keep in sync with the source. |
| 42 | CMD ["node", "--no-warnings=ExperimentalWarning", "server/index.ts"] |