diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 98cbfca..3b7e488 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,3 +1,4 @@ +# ---- base stage ---- FROM node:22-alpine AS base ENV PNPM_HOME="/pnpm" @@ -5,8 +6,13 @@ 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__ WORKDIR /app @@ -14,27 +20,31 @@ COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile -# ---- runner stage ---- -FROM base AS runner +COPY . . -WORKDIR /app +RUN pnpm build -ENV NODE_ENV=production +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 -# accepts version argument to override package.json version -ARG VERSION="" +# ---- runner stage ---- +FROM base AS runner -# accepts build date argument to set package.json build metadata +ARG VERSION="" ARG BUILD_DATE="" -COPY --from=deps /app/node_modules ./node_modules -COPY . . +WORKDIR /app + +COPY --from=builder /app . -# 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 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 0000000..2244a44 --- /dev/null +++ b/frontend/entrypoint.sh @@ -0,0 +1,38 @@ +#!/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 + 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" + 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 a4f350d..2e26b08 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 bacff58..102f8b8 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 ||