From bbba2a5d1e698a82cbe573b1f454775c96be4970 Mon Sep 17 00:00:00 2001 From: orenzhang <41963680+OrenZhang@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:07:50 +0800 Subject: [PATCH 1/3] chore(build): pre-build Next.js to boost startup time --- frontend/Dockerfile | 41 +++++++++++++++++++++++------------------ frontend/entrypoint.sh | 36 ++++++++++++++++++++++++++++++++++++ frontend/next.config.ts | 2 +- frontend/proxy.ts | 2 +- 4 files changed, 61 insertions(+), 20 deletions(-) create mode 100755 frontend/entrypoint.sh diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 98cbfca7..9ecc2457 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,3 +1,4 @@ +# ---- base stage ---- FROM node:22-alpine AS base ENV PNPM_HOME="/pnpm" @@ -5,36 +6,40 @@ ENV PATH="$PNPM_HOME:$PATH" RUN corepack enable && corepack prepare pnpm@10.10.0 --activate -# ---- deps stage ---- -FROM base AS deps +# ---- build stage ---- +FROM base AS builder + +ENV NODE_ENV=production +ENV NEXT_PUBLIC_LINUX_DO_CREDIT_BACKEND_URL=https://build-placeholder.invalid +ENV LINUX_DO_CREDIT_SESSION_COOKIE_NAME=__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__ +ENV LINUX_DO_CREDIT_RATE_LIMIT_ENABLED=__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__ + +ARG VERSION="" +ARG BUILD_DATE="" WORKDIR /app COPY package.json pnpm-lock.yaml ./ +COPY patches ./patches + +RUN if [ -n "$VERSION" ] || [ -n "$BUILD_DATE" ]; then \ + VERSION="$VERSION" BUILD_DATE="$BUILD_DATE" node -e "const fs = require('fs'); const pkg = require('./package.json'); const version = process.env.VERSION; const buildDate = process.env.BUILD_DATE; if (version) pkg.version = version; if (buildDate) pkg.buildDate = buildDate; fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n')"; \ +fi RUN pnpm install --frozen-lockfile +COPY . . + +RUN pnpm build + # ---- runner stage ---- FROM base AS runner WORKDIR /app -ENV NODE_ENV=production - -# accepts version argument to override package.json version -ARG VERSION="" - -# accepts build date argument to set package.json build metadata -ARG BUILD_DATE="" - -COPY --from=deps /app/node_modules ./node_modules -COPY . . - -# update package.json build metadata when build args are provided -RUN if [ -n "$VERSION" ] || [ -n "$BUILD_DATE" ]; then \ - VERSION="$VERSION" BUILD_DATE="$BUILD_DATE" node -e "const fs = require('fs'); const pkg = require('./package.json'); const version = process.env.VERSION; const buildDate = process.env.BUILD_DATE; if (version) pkg.version = version; if (buildDate) pkg.buildDate = buildDate; fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n')"; \ -fi +COPY --from=builder /app . EXPOSE 3000 -CMD ["sh", "-c", "pnpm build && pnpm start"] +ENTRYPOINT ["./entrypoint.sh"] +CMD ["pnpm", "start"] diff --git a/frontend/entrypoint.sh b/frontend/entrypoint.sh new file mode 100755 index 00000000..595ca8af --- /dev/null +++ b/frontend/entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +set -e + +replace_placeholder() { + local placeholder="$1" + local real_value="$2" + + if [ -z "$real_value" ]; then + echo "⚠️ WARNING: Environment variable for placeholder '${placeholder}' is not set. Skipping replacement." + return 0 + fi + + echo "🔍 Replacing placeholder '${placeholder}' with value '${real_value}'" + + local escaped + escaped=$(printf '%s\n' "$real_value" | sed 's/[&/\]/\\&/g') + + local files + files=$(grep -rl "$placeholder" /app/.next || true) + + if [ -z "$files" ]; then + echo "⚠️ WARNING: placeholder '${placeholder}' not found in any file" + else + local count + count=$(echo "$files" | wc -l) + echo "$files" | xargs sed -i "s|${placeholder}|${escaped}|g" + echo "✅ Replaced '${placeholder}' in ${count} file(s)" + fi +} + +replace_placeholder "https://build-placeholder.invalid" "$NEXT_PUBLIC_LINUX_DO_CREDIT_BACKEND_URL" +replace_placeholder "__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__" "$LINUX_DO_CREDIT_SESSION_COOKIE_NAME" +replace_placeholder "__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__" "$LINUX_DO_CREDIT_RATE_LIMIT_ENABLED" + +exec "$@" diff --git a/frontend/next.config.ts b/frontend/next.config.ts index a4f350d7..2e26b08f 100644 --- a/frontend/next.config.ts +++ b/frontend/next.config.ts @@ -5,7 +5,7 @@ const nextConfig: NextConfig = { experimental: { }, async rewrites() { - const backendUrl = process.env.LINUX_DO_CREDIT_BACKEND_URL || 'http://localhost:8000'; + const backendUrl = process.env.NEXT_PUBLIC_LINUX_DO_CREDIT_BACKEND_URL || 'http://localhost:8000'; return [ // 易支付兼容接口 - 创建订单 { diff --git a/frontend/proxy.ts b/frontend/proxy.ts index bacff58a..102f8b8b 100644 --- a/frontend/proxy.ts +++ b/frontend/proxy.ts @@ -86,7 +86,7 @@ export function proxy(request: NextRequest) { /* API 请求:速率限制后放行 */ if (pathname.startsWith('/api/')) { - const rateLimitEnabled = !!process.env.LINUX_DO_CREDIT_RATE_LIMIT_ENABLED + const rateLimitEnabled = process.env.LINUX_DO_CREDIT_RATE_LIMIT_ENABLED === 'true' if (rateLimitEnabled && shouldRateLimit(pathname)) { const identifier = sessionCookie?.value || From a5941240d13321a57d79cfeb6c85f5e6b764efda Mon Sep 17 00:00:00 2001 From: orenzhang <41963680+OrenZhang@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:59:48 +0800 Subject: [PATCH 2/3] chore(build_image): streamline build date handling in Dockerfile --- frontend/Dockerfile | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 9ecc2457..3b7e4886 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -14,17 +14,9 @@ ENV NEXT_PUBLIC_LINUX_DO_CREDIT_BACKEND_URL=https://build-placeholder.invalid ENV LINUX_DO_CREDIT_SESSION_COOKIE_NAME=__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__ ENV LINUX_DO_CREDIT_RATE_LIMIT_ENABLED=__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__ -ARG VERSION="" -ARG BUILD_DATE="" - WORKDIR /app COPY package.json pnpm-lock.yaml ./ -COPY patches ./patches - -RUN if [ -n "$VERSION" ] || [ -n "$BUILD_DATE" ]; then \ - VERSION="$VERSION" BUILD_DATE="$BUILD_DATE" node -e "const fs = require('fs'); const pkg = require('./package.json'); const version = process.env.VERSION; const buildDate = process.env.BUILD_DATE; if (version) pkg.version = version; if (buildDate) pkg.buildDate = buildDate; fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n')"; \ -fi RUN pnpm install --frozen-lockfile @@ -32,13 +24,26 @@ COPY . . RUN pnpm build +RUN grep -rl \ + -e "https://build-placeholder.invalid" \ + -e "__LINUX_DO_CREDIT_SESSION_COOKIE_NAME__" \ + -e "__LINUX_DO_CREDIT_RATE_LIMIT_ENABLED__" \ + /app/.next > /app/.replace.files + # ---- runner stage ---- FROM base AS runner +ARG VERSION="" +ARG BUILD_DATE="" + WORKDIR /app COPY --from=builder /app . +RUN if [ -n "$VERSION" ] || [ -n "$BUILD_DATE" ]; then \ + VERSION="$VERSION" BUILD_DATE="$BUILD_DATE" node -e "const fs = require('fs'); const pkg = require('./package.json'); const version = process.env.VERSION; const buildDate = process.env.BUILD_DATE; if (version) pkg.version = version; if (buildDate) pkg.buildDate = buildDate; fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\\n')"; \ +fi + EXPOSE 3000 ENTRYPOINT ["./entrypoint.sh"] From 0ac6a44ef258b146b4787269696415e36831b1bc Mon Sep 17 00:00:00 2001 From: orenzhang <41963680+OrenZhang@users.noreply.github.com> Date: Wed, 29 Apr 2026 23:02:20 +0800 Subject: [PATCH 3/3] chore(entrypoint): update file search logic to use .replace.files if available --- frontend/entrypoint.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/entrypoint.sh b/frontend/entrypoint.sh index 595ca8af..2244a442 100755 --- a/frontend/entrypoint.sh +++ b/frontend/entrypoint.sh @@ -17,7 +17,9 @@ replace_placeholder() { escaped=$(printf '%s\n' "$real_value" | sed 's/[&/\]/\\&/g') local files - files=$(grep -rl "$placeholder" /app/.next || true) + if [ -f /app/.replace.files ]; then + files=$(grep -l "$placeholder" $(cat /app/.replace.files) 2>/dev/null || true) + fi if [ -z "$files" ]; then echo "⚠️ WARNING: placeholder '${placeholder}' not found in any file"