本地 npm run build 绿。Vercel 显示 “Build failed”。郁闷,但失败模式有限。6 个类别覆盖 95% 的真实失败,知道在哪看 build 日志就能定位到哪一类。下面给出每类的日志关键词、诊断命令和配置修复。
问题背景
Vercel 在干净的 Linux 容器里跑 build,用你指定的 Node 版本(默认 20 LTS)。和本地差异——Node 版本、环境变量、路径大小写敏感、npm 源——都是常见元凶。Build log 里最后失败的那步基本就是真实原因。
判断标准
日志字符串 → 类别
"Cannot find module" → 依赖或路径大小写
"process is not defined" → Production 缺环境变量
"Type error" → TypeScript 比本地严
"Killed"(无其它信息) → 内存不足(OOM)
build 跑超 45 分钟后挂 → 超时
"Module not found: Error: Can't ..." → 依赖或 alias
昨天能 build 今天挂 → 缓存陈旧或依赖飘了
快速结论
先读 build log 里失败那步,再对到上面的分类,跳到对应修复方案。
开始前准备
- 打开失败 deployment 页,复制失败日志行。
package.json和vercel.json摆在眼前。- 知道本地 Node 版本(
node -v)。
实操步骤
-
读失败那步。 Build Logs → 搜 “error” 或滚到最底部红色块。失败退出前一行通常就是真因。
-
Pin Node 版本。
package.json:
{
"engines": { "node": "20.x" },
"scripts": { "build": "astro build" }
}
commit 后重新部署,Vercel 严格按 engines.node 跑。
- 补缺的环境变量。 Vercel Dashboard → Project → Settings → Environment Variables → 加 Production(也可加 Preview)。然后重新部署。Vercel CLI:
vercel env add OPENAI_API_KEY production
# 按提示粘贴 secret
vercel env add SITE_URL production
# https://yourdomain.com
vercel --prod # 触发干净部署
- 类型错误本地先复现:
npx tsc --noEmit
# tsconfig.json 有 "strict": true 时与 Vercel 一致
要么改代码,要么 strictness 是误开就放松:
{
"compilerOptions": {
"strict": true,
"skipLibCheck": true,
"noUncheckedIndexedAccess": false
}
}
- 依赖 / 路径错位。 lockfile 飘是经典:
rm -rf node_modules package-lock.json
npm install
git add package-lock.json
git commit -m "fix: refresh lockfile"
Vercel 里 Deployments → Redeploy → 取消 “Use existing build cache” 强制干净安装。日志也留意路径大小写——./Components/Foo vs ./components/Foo 在 macOS 行、Vercel Linux 挂。
- OOM(“Killed”)。 降低 build 内存使用,Astro:
// astro.config.mjs
export default defineConfig({
build: {
concurrency: 1, // 串行生成页面
inlineStylesheets: 'never',
},
image: { service: { entrypoint: 'astro/assets/services/sharp' } },
});
Next.js:临时加 Node 堆(package.json):
{
"scripts": {
"build": "NODE_OPTIONS='--max-old-space-size=4096' next build"
}
}
Vercel Pro 内存上限更高;Hobby 限制更紧。
- 超时。 Hobby 45 分钟硬上限。内容站撞顶就拆 build(按语言或按板块),或者升 Pro。常用技巧:
// astro.config.mjs —— 每次 build 限制静态页面数
export default defineConfig({
build: { format: 'directory' },
// 单次只生成最近 N 篇;老的走单独部署
});
- 同一个改动先在本地能 build。 本地可重现失败能极大缩短迭代时间:
npm ci # 按 lockfile 干净安装
npm run build # 完全匹配 Vercel 的 build 命令
执行检查清单
package.json设了engines.node。- Production 和任何其它会 build 的环境都有所需变量。
tsc --noEmit本地通过。- lockfile 已 commit 且最新。
- 改完 env / 配置后第一次重新部署用 “no cache”。
上线后验证
- 修完后下一次部署绿色完成。
- build log 里不再有之前的错误字符串。
- build 时间在套餐上限内。
容易踩的坑
- 只看 build log 最下面——真实错误往往在中间。
- 环境变量只加 Preview 没加 Production(或反过来)然后纳闷。
- 把
node_modules提交到仓库去”修”依赖错——仓库变大、build 更慢。 - 为绕一个类型错全局关 TypeScript 严格模式——问题往后推。
- 为”先上线”改 build 命令跳过 lint / 测试——失败会以运行时崩溃形式再来。
FAQ
- 怎么找到真正的错误信息?: deployment 页打开 Build Logs,搜 “error”。第一个匹配通常就是原因。
- 本地能 build Vercel 挂,怎么办?: Node 版本不同、缺环境变量、路径大小写敏感,或你本地有的 peer 依赖但 lockfile 里没。
- 不改代码能重跑 build 吗?: 能。Deployments → 选失败那次 → “Redeploy”,可以勾掉 “use existing build cache”。
- “Killed” 是什么意思?: OOM。减小 bundle、减少图片集、减少同时生成的页面,或升级拿更多内存。
- 能本地跑 Vercel 的 build 容器吗?: 近似可以,Vercel CLI:
vercel build --prod再vercel deploy --prebuilt --prod,环境很接近。