Next.js 16 + Contentlayer 在 Vercel 部署失败的解决方案
CuiJi
问题背景
最近将博客项目升级到 Next.js 16 后遇到了一个典型的问题:本地构建完全正常,但在 Vercel 上部署时却失败了。
错误信息如下:
Error: Turbopack build failed with 8 errors:
Module not found: Can't resolve 'contentlayer/generated'
这个问题发生在多个页面中:
./app/about/page.tsx./app/blog/[...slug]/page.tsx./app/blog/page.tsx./app/sitemap.ts- 等等...
问题分析
通过分析 Vercel 部署日志,发现关键问题指向Turbopack 是默认构建工具
▲ Next.js 16.1.6 (Turbopack)
Creating an optimized production build ...
Next.js 16 默认使用 Turbopack 作为构建工具,而不是传统的 webpack。
Contentlayer 生成流程
项目使用 contentlayer2 来处理 MDX 文件,它会:
- 读取
data/blog/目录下的所有 MDX 文件 - 解析 frontmatter 和内容
- 生成 TypeScript 类型定义
- 输出到
.contentlayer/generated目录
这个目录被 .gitignore 忽略,需要在每次构建时重新生成。
兼容性问题
核心问题:Turbopack 与 contentlayer2 不兼容
Turbopack 在生产构建时无法正确处理 contentlayer 动态生成的模块。具体表现为:
- 无法解析
contentlayer/generated模块 - 即使有
withContentlayer包装器也无济于事 - Turbopack 不支持 webpack 的某些特性
解决方案:强制使用 webpack
修改 package.json 的 build 脚本:
添加 --webpack 标志强制 Next.js 使用 webpack 而不是 Turbopack。
方案 2:配置 Next.js
修改 next.config.js,添加 transpilePackages 配置:
module.exports = () => {
const plugins = [withContentlayer, withBundleAnalyzer]
return plugins.reduce((acc, next) => next(acc), {
// ... 其他配置
transpilePackages: ['contentlayer2', 'next-contentlayer2'],
// 注释掉 turbopack 配置
// turbopack: {},
})
}
方案 3:配置 Vercel 部署
创建 vercel.json 文件:
{
"buildCommand": "yarn build",
"installCommand": "corepack enable && yarn install --frozen-lockfile",
"framework": "nextjs",
"env": {
"NEXT_DISABLE_TURBOPACK_IN_PRODUCTION": "1"
}
}
关键点:
- 使用 Corepack - 项目使用 Yarn 3.6.1(Yarn Berry),需要通过
corepack enable启用 - 锁定 Node 版本 - 创建
.nvmrc文件指定 Node 版本(推荐 20)
# .nvmrc
20
验证结果
本地构建测试
$ yarn build
▲ Next.js 16.1.6 (webpack)
Creating an optimized production build ...
Generated 25 documents in .contentlayer
✓ Compiled successfully in 11.2s
✓ Generating static pages (135/135) in 1090.1ms
RSS feed generated...
✅ 成功!
技术细节
为什么 Turbopack 会导致问题?
Turbopack 是 Next.js 团队开发的新一代构建工具,用 Rust 编写,性能更优。但它目前还有一些限制:
- 不完全支持所有 webpack 特性 - 特别是自定义的 webpack loaders 和 plugins
- 模块解析机制不同 - 对于动态生成的模块支持有限
- 生态还在发展中 - 许多第三方包还未完全适配
为什么 webpack 可以工作?
webpack 是成熟的构建工具,对以下场景有良好支持:
- ✅ 自定义 loaders(如
@svgr/webpack) - ✅ 动态代码生成
- ✅ 复杂的模块解析
- ✅ Contentlayer 的插件系统
Next.js 16 的变化
Next.js 16 开始默认启用 Turbopack,但提供了回退选项:
# 显式使用 Turbopack
next build --turbopack
# 显式使用 webpack
next build --webpack
如果项目依赖于 webpack 特性,需要明确指定使用 webpack。
经验总结
1. 开发环境 vs 生产环境
这个问题在开发环境中没有出现,原因是:
- 开发模式使用
next dev,可能有不同的模块加载机制 - 生产构建
next build更严格,需要完整的模块依赖树 - CI/CD 环境与本地环境可能有细微差异
2. 升级建议
在升级 Next.js 主版本时,特别是升级到 Next.js 15/16:
- 阅读发布日志 - 了解 breaking changes
- 检查依赖兼容性 - 特别是 contentlayer 这样的关键依赖
- 本地测试完整构建 - 不仅仅是
next dev - 准备部署配置 - 提前配置 Vercel 或其他平台
3. 调试技巧
遇到类似问题时:
# 1. 查看详细的构建日志
yarn build --debug
# 2. 清除缓存重新构建
rm -rf .next
yarn build
# 3. 对比本地和 CI 环境
echo $NODE_VERSION
node --version