From de857190d706883c9a9250abddb38222c4fa7bf5 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sun, 9 Aug 2026 17:34:43 +0800 Subject: [PATCH] fix staging web image publish --- deploy/railway-web.Dockerfile | 8 ++++--- frontend/next.config.ts | 1 + .../tests/staging-backend-workflows.test.ts | 22 +++++++++++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/deploy/railway-web.Dockerfile b/deploy/railway-web.Dockerfile index 627b1936..d1ad79fa 100644 --- a/deploy/railway-web.Dockerfile +++ b/deploy/railway-web.Dockerfile @@ -21,16 +21,18 @@ COPY references /app/references COPY scripts /app/scripts COPY skills /app/skills -RUN npm run build && npm prune --omit=dev +RUN npm run build FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/library/node:22-alpine WORKDIR /app/frontend -COPY --from=build /app /app +COPY --from=build /app/frontend/.next/standalone /app +COPY --from=build /app/frontend/.next/static /app/frontend/.next/static +COPY --from=build /app/frontend/public /app/frontend/public ARG NEXT_PUBLIC_SUPABASE_URL ARG NEXT_PUBLIC_SUPABASE_ANON_KEY ENV NEXT_PUBLIC_SUPABASE_URL=${NEXT_PUBLIC_SUPABASE_URL} \ NEXT_PUBLIC_SUPABASE_ANON_KEY=${NEXT_PUBLIC_SUPABASE_ANON_KEY} ENV NODE_ENV=production -CMD ["sh", "-c", "exec npm start -- --hostname 0.0.0.0 --port \"${PORT:-3000}\""] +CMD ["node", "server.js"] diff --git a/frontend/next.config.ts b/frontend/next.config.ts index 7b8ac910..9d6ea8ff 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -6,6 +6,7 @@ const repositoryRoot = path.join(process.cwd(), ".."); const nextConfig: NextConfig = { devIndicators: false, experimental: { authInterrupts: true }, + output: "standalone", turbopack: { root: repositoryRoot }, outputFileTracingRoot: repositoryRoot, outputFileTracingIncludes: { diff --git a/frontend/tests/staging-backend-workflows.test.ts b/frontend/tests/staging-backend-workflows.test.ts index 3ca104f5..dc2d5de6 100644 --- a/frontend/tests/staging-backend-workflows.test.ts +++ b/frontend/tests/staging-backend-workflows.test.ts @@ -82,6 +82,11 @@ const productionDatabaseEnvValidator = new URL( "../../deploy/validate-production-database-env.sh", import.meta.url, ); +const railwayWebDockerfile = new URL( + "../../deploy/railway-web.Dockerfile", + import.meta.url, +); +const nextConfig = new URL("../next.config.ts", import.meta.url); function read(url: URL): string { return readFileSync(url, "utf8"); @@ -121,6 +126,23 @@ test("changed staging workflows are syntactically valid YAML", () => { } }); +test("railway web image uses Next standalone runtime output", () => { + const dockerfile = read(railwayWebDockerfile); + const config = read(nextConfig); + + assert.match(config, /output: "standalone"/); + assert.match(config, /outputFileTracingRoot: repositoryRoot/); + assert.match(dockerfile, /RUN npm run build\n/); + assert.doesNotMatch(dockerfile, /npm prune --omit=dev/); + assert.match(dockerfile, /COPY --from=build \/app\/frontend\/\.next\/standalone \/app/); + assert.match(dockerfile, /COPY --from=build \/app\/frontend\/\.next\/static \/app\/frontend\/\.next\/static/); + assert.match(dockerfile, /COPY --from=build \/app\/frontend\/public \/app\/frontend\/public/); + assert.doesNotMatch(dockerfile, /COPY --from=build \/app \/app/); + assert.match(dockerfile, /WORKDIR \/app\/frontend/); + assert.match(dockerfile, /CMD \["node", "server\.js"\]/); + assert.doesNotMatch(dockerfile, /npm start/); +}); + test("quality gate validates relevant changes once and publishes a digest manifest", () => { const workflow = read(qualityWorkflow);