先确认超时发生在哪一段
先打开 Vercel 的 Build Logs,看最后 30 行,确认超时发生在什么时候。不要急着改代码。
| 日志位置 | 常见现象 | 第一刀 |
|---|---|---|
| Installing dependencies | pnpm install 很久不动 | 锁版本、删无用依赖、跳过下载型 postinstall |
| Building | next build 卡在某个 route | 找 fetch、generateStaticParams、CMS 请求 |
| Collecting page data | 某些页面一直等 | 缩小静态生成范围,失败时返回空态 |
| Build hook | webhook 已发但部署没开始 | 查分支、token、触发频率 |
如果日志里出现 fetch failed、ETIMEDOUT、ECONNRESET,说明构建容器在访问外部服务时失败。这里的外部服务可能是 CMS、Supabase、Stripe、内部 API,也可能只是 npm registry。
最短处理路径
先锁住包管理器。仓库里只留一个 lockfile,Vercel 项目里也选同一个。Node 版本写进 package.json 或 .nvmrc,别让本地是 20,线上突然跑 22。
再拿掉会下载大二进制的 postinstall。Puppeteer、Playwright、Sharp 的 native 编译都可能拖慢。真的需要浏览器,就放到运行时镜像或单独任务里。
接着搜 build 阶段 fetch。重点看这些位置:
export async function generateStaticParams() {}
export const revalidate = 3600
fetch("https://api.example.com/products")
如果这个 API 是你自己的后端,构建时还没部署好,就会互相等。给 build 请求加 5-8 秒 timeout,失败返回最小数据集,让页面先能发版。
最后,build hook 要幂等。CMS 发布一次文章,不要连打 5 个 hook。脚本里加退避,记录 Vercel 返回的 deployment id,失败再重试。
为什么 build 阶段怕外部 API?
本地跑 next build 时,你可能正连着公司网络、数据库白名单、缓存也热。Vercel 构建容器是干净环境,只知道环境变量和仓库文件。只要一个 API 慢,整个部署就慢。
我现在的习惯:营销页、文档页可以静态生成;用户态数据不要在 build 拉;价格表这类半静态数据可以预取,但必须有 fallback。构建失败影响发版,比页面晚几秒刷新更伤。
Vercel build timeout 继续排查清单
- Vercel 环境变量是否在 Production 和 Preview 都配置了
- 外部 API 是否限制了 Vercel 构建出口 IP
fetch是否没有 timeout,导致一直挂起- CMS webhook 是否触发到了错误分支
- monorepo 的 Root Directory 是否选错
npm_config_registry是否被写成不可用镜像
我还会单独看一次缓存命中。很多项目把 package.json、lockfile、源码、生成物一次性 COPY,任何小改动都会让依赖缓存失效。Vercel 自动构建不等于自动帮你省时间,monorepo 尤其明显。要是某个包只有后台任务会用,就别让前台站点安装它。
另一个常被忽略的是 preview 环境。你在 production 配了 CMS token,preview 没配,PR 部署就会在 build 里拿空 token 去请求接口。日志里看起来像 fetch 超时,实际是上游一直等鉴权或返回重定向。排查时把 Production、Preview、Development 三组变量列成表,逐项对。
最后看一次外部 API 的失败策略。构建脚本里不要直接 await fetch() 然后相信它永远成功。给请求加超时、默认值和清楚的错误日志。我的底线是:缺一篇博客可以晚点更新,不能因为一篇博客拉不下来,整站都发不了版。发布系统要允许部分内容暂时缺席,而不是把所有页面绑在同一个外部请求上。
还没恢复时,单独查 Vercel build timeout
把关键页面从 build-time fetch 改成 runtime fetch,发一个能启动的版本。再把慢接口拆到后台任务,构建只读缓存文件或最小 JSON。跨地区协作时,Vercel、GitHub 和 CMS 后台最好用固定环境排查;需要稳定处理部署面板、GitHub Actions 和 Cloudflare,可以准备海外服务跑 GitHub Actions / Cloudflare 的稳定线路。