-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
73 lines (70 loc) · 3.69 KB
/
Copy pathDockerfile
File metadata and controls
73 lines (70 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
FROM node:22.16.0-alpine AS base
RUN corepack enable
WORKDIR /app
FROM base AS dependencies
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY apps ./apps
COPY packages ./packages
RUN pnpm install --frozen-lockfile
FROM dependencies AS builder
ARG APP=web
COPY turbo.json tsconfig.base.json ./
RUN pnpm --filter "@w3ds/${APP}" build
# The standalone server traces database query modules, but not Drizzle's migration
# reader because it only runs in Railway's pre-deploy phase. Add those two small
# runtime modules and workspace links to the standalone artifact so migrations run
# with the same locked pg and drizzle-orm versions as the application.
RUN if [ "${APP}" = "web" ]; then \
set -eux; \
standalone="apps/${APP}/.next/standalone"; \
drizzle_source="$(find node_modules/.pnpm -maxdepth 1 -type d -name 'drizzle-orm@*' -print -quit)"; \
drizzle_target="$(find "${standalone}/node_modules/.pnpm" -maxdepth 1 -type d -name 'drizzle-orm@*' -print -quit)"; \
pg_target="$(find "${standalone}/node_modules/.pnpm" -maxdepth 1 -type d -name 'pg@*' -print -quit)"; \
test -n "${drizzle_source}"; \
test -n "${drizzle_target}"; \
test -n "${pg_target}"; \
cp "${drizzle_source}/node_modules/drizzle-orm/migrator.js" "${drizzle_target}/node_modules/drizzle-orm/migrator.js"; \
cp "${drizzle_source}/node_modules/drizzle-orm/node-postgres/migrator.js" "${drizzle_target}/node_modules/drizzle-orm/node-postgres/migrator.js"; \
mkdir -p "${standalone}/apps/${APP}/node_modules"; \
ln -s "../../../node_modules/.pnpm/$(basename "${drizzle_target}")/node_modules/drizzle-orm" "${standalone}/apps/${APP}/node_modules/drizzle-orm"; \
ln -s "../../../node_modules/.pnpm/$(basename "${pg_target}")/node_modules/pg" "${standalone}/apps/${APP}/node_modules/pg"; \
fi
# Railway runs the migration in the standalone runner before the application
# starts. Bundle its TypeScript entrypoint into one Node 22 ESM file instead of
# compiling a bare entrypoint: `tsc` preserves extensionless internal imports
# and therefore produces a runner that Node cannot execute outside the source
# tree. Keep pg and drizzle external because the standalone image already
# provides the locked runtime copies used by the application itself.
RUN if [ "${APP}" = "web" ]; then \
set -eux; \
migration_runtime="apps/${APP}/.next/migration-runtime"; \
pnpm exec esbuild "apps/${APP}/src/server/db/migrate.ts" \
--bundle \
--platform=node \
--format=esm \
--target=node22 \
--external:pg \
--external:drizzle-orm \
"--external:drizzle-orm/*" \
--outfile="${migration_runtime}/migrate.mjs"; \
fi
FROM node:22.16.0-alpine AS runner
# The long-recording player joins source segments with ffmpeg. Keep the
# executable in the runtime image (not only a developer machine), otherwise
# every continuous recording fails after a successful ticket is issued.
RUN apk add --no-cache ffmpeg
ENV NODE_ENV=production
WORKDIR /app
ARG APP=web
ENV APP=${APP}
COPY --from=builder /app/apps/${APP}/.next/standalone ./
COPY --from=builder /app/apps/${APP}/.next/static ./apps/${APP}/.next/static
COPY --from=builder /app/apps/${APP}/public ./apps/${APP}/public
# Railway's builder accepts standard COPY stages but not BuildKit's
# RUN --mount=from=<stage>. These files are needed only by the pre-deploy
# migration command and remain inside the server-side standalone artifact.
COPY --from=builder /app/apps/${APP}/.next/migration-runtime/migrate.mjs ./apps/${APP}/src/server/db/migrate.mjs
COPY --from=builder /app/apps/${APP}/drizzle ./apps/${APP}/drizzle
EXPOSE 3000
ENV PORT=3000 HOSTNAME=0.0.0.0
CMD ["sh", "-c", "node apps/${APP}/server.js"]