Next.js金丝雀版部署Vercel时卡在生成静态页面,构建失败
Next.js金丝雀版Vercel部署卡住静态页面生成阶段的解决办法
问题现象
使用最新Next.js金丝雀版本部署到Vercel时,构建流程卡在Generating static pages阶段:
Creating an optimized production build ... ✓ Compiled successfully Skipping linting Checking validity of types ... Collecting page data ... Generating static pages (0/15) ... Generating static pages (3/15)
本地构建可正常完成,但Vercel最终构建失败,报错如下:
Export encountered an error on /api/webhooks/clerk/route: /api/webhooks/clerk, exiting the build. ⨯ Next.js build worker exited with code: 1 and signal: null Error: Command "npm run build" exited with 1
相关配置与代码
next.config.js
// @ts-check /** @type {import('next').NextConfig} */ const nextConfig = { images: { remotePatterns: [{ protocol: 'http', hostname: 'localhost' }, { protocol: 'https', hostname: 'b.stripecdn.com' }, { protocol: 'https', hostname: 'yt3.googleusercontent.com' }, { protocol: 'https', hostname: 'i.ytimg.com' }, ], // Allow images from localhost and Stripe CDN }, eslint: { ignoreDuringBuilds: true, }, /* config options here */ experimental: { dynamicIO: true, authInterrupts: true, }, // staticPageGenerationTimeout: 1000, } module.exports = nextConfig
Clerk Webhook路由文件(route.ts)
import { env } from "@/data/env/server" import { deleteUser, insertUser, updateUser } from "@/features/users/db/users" import { syncClerkUserMetadata } from "@/services/clerk" import { WebhookEvent } from "@clerk/nextjs/server" import { headers } from "next/headers" import { Webhook } from "svix" export async function POST(req: Request) { const headerPayload = await headers() const svixId = headerPayload.get("svix-id") const svixTimestamp = headerPayload.get("svix-timestamp") const svixSignature = headerPayload.get("svix-signature") if (!svixId || !svixTimestamp || !svixSignature) { return new Response("Error occurred -- no svix headers", { status: 400, }) } const payload = await req.json() const body = JSON.stringify(payload) const wh = new Webhook(env.CLERK_WEBHOOK_SECRET) let event: WebhookEvent try { event = wh.verify(body, { "svix-id": svixId, "svix-timestamp": svixTimestamp, "svix-signature": svixSignature, }) as WebhookEvent } catch (err) { console.error("Error verifying webhook:", err) return new Response("Error occurred", { status: 400, }) } switch (event.type) { case "user.created": case "user.updated": { const email = event.data.email_addresses.find( email => email.id === event.data.primary_email_address_id )?.email_address const name = `${event.data.first_name} ${event.data.last_name}`.trim() if (email == null) return new Response("No email", { status: 400 }) if (name === "") return new Response("No name", { status: 400 }) if (event.type === "user.created") { const user = await insertUser({ clerkUserId: event.data.id, email, name, imageUrl: event.data.image_url, role: "user", }) await syncClerkUserMetadata(user) } else { await updateUser({ clerkUserId: event.data.id }, { email, name, imageUrl: event.data.image_url, role: event.data.public_metadata.role, }) } break } case "user.deleted": { if (event.data.id != null) { await deleteUser({ clerkUserId: event.data.id }) } break } } return new Response("", { status: 200 }) }
解决步骤
标记API路由为动态路由:Webhook路由需要处理动态请求,Next.js金丝雀版的静态生成逻辑会尝试分析该路由,导致卡住。在
route.ts顶部添加以下代码,强制跳过静态生成:export const dynamic = 'force-dynamic'检查环境变量配置:确认Vercel项目的
Settings > Environment Variables中已正确设置CLERK_WEBHOOK_SECRET,且勾选了Preview和Production环境,避免构建时因变量缺失导致验证失败。延长静态生成超时时间:取消
next.config.js中staticPageGenerationTimeout的注释,调整为更长时间(如30秒):staticPageGenerationTimeout: 30000,临时禁用实验性特性排查:如果上述方法无效,可暂时注释掉
experimental中的dynamicIO和authInterrupts,确认是否为实验性功能的兼容性问题:experimental: { // dynamicIO: true, // authInterrupts: true, },
验证方法
本地执行npm run build确认无异常后,重新部署到Vercel,观察构建流程是否正常完成。
内容的提问来源于stack exchange,提问作者Amen Ra
相关产品推荐
相关产品推荐

