在首页 (/) 使用预渲染 (prerender: true) 时,页面需要调用 API 接口,而 API 的 baseURL 是通过 runtimeConfig 从环境变量中获取的。打包 Docker 镜像后运行,报错找不到 output 目录下的 index.mjs 文件。
预渲染(Prerender)发生在构建阶段,此时:
runtimeConfig.public.API_BASE_URL 的值为空字符串 ''index.mjs 文件未能正确生成// nuxt.config.ts 原配置
runtimeConfig: {
public: {
API_BASE_URL: '' // 构建时为空,运行时才从 env 注入
}
},
routeRules: {
'/': { prerender: true } // ❌ 预渲染时拿不到环境变量
}
| 特性 | 预渲染 (Prerender) | ISR / SSR |
|---|---|---|
| 执行时机 | 构建阶段 | 运行阶段 |
| 环境变量可用性 | ❌ 不可用 | ✅ 可用 |
| 适用场景 | 纯静态页面 | 动态数据页面 |
将预渲染改为 ISR(增量静态再生) 或 SSR:
// nuxt.config.ts 修改后
routeRules: {
// '/': { prerender: true }, // ❌ 注释掉
'/': { isr: 60 * 60 * 1 } // ✅ 使用 ISR,缓存 1 小时
}
routeRules: {
// 预渲染 - 仅适用于不依赖环境变量的静态页面
'/about': { prerender: true },
// ISR - 适用于需要环境变量且数据更新不频繁的页面
'/': { isr: 3600 }, // 缓存 1 小时
'/products': { isr: 1800 }, // 缓存 30 分钟
// SSR - 适用于数据实时性要求高的页面
'/dashboard': { ssr: true }
}
文档站在本地 build 后预览正常,但是部署到测试环境后,直接访问深层文档链接失败。
示例:
https://developer.dev.tripguru.ai/docs/mcp-agents/setup
表现为:
/docs/mcp-agents/setup 不正常。Nuxt Content 在服务端运行时会使用 SQLite 作为内容查询数据库。
如果配置为文件型 SQLite,例如:
export default defineNuxtConfig({
content: {
database: {
filename: '/tmp/contents.sqlite'
}
}
})
那么 SSR 直接访问深层 docs 页面时,服务端需要打开或创建 SQLite 文件。
如果容器文件系统是只读的,运行时无法写入 SQLite 文件,会出现:
SQLITE_CANTOPEN: unable to open database file
最终页面可能表现为 404 Documentation page not found。
基于当前项目用 Docker 验证了 4 种情况:
| 场景 | 文件系统 | 渲染方式 | 直接访问 /docs/mcp-agents/setup | 结论 |
|---|---|---|---|---|
| 当前项目使用 prerender | 只读 | crawl prerender | 构建失败 | 不能直接作为可部署方案 |
| 当前项目不使用 prerender | 只读 | SSR | 失败,返回 404 | 不可行 |
| 当前项目不使用 prerender | 可写 | SSR | 成功,返回 200 | 可行 |
| 当前项目给 docs 使用 prerender | 只读 | docs 静态预渲染 | 成功,返回 200 | 可行 |
容器运行时加 --read-only,直接请求:
/docs/mcp-agents/setup
结果失败,页面返回 404 Documentation page not found,日志出现:
SQLITE_CANTOPEN: unable to open database file
说明只读文件系统会导致 Nuxt Content 的文件型 SQLite 无法打开。
同样的 SSR deep link,在容器文件系统可写时返回 200。
说明代码逻辑本身没有问题,问题点在运行时写入 SQLite 文件。
如果将 /docs/** 预渲染成静态 HTML,直接访问 /docs/mcp-agents/setup 返回 200。
因为页面已经在构建阶段生成,运行时不需要再查询 SQLite。
使用 crawlLinks: true 时,构建过程中确实爬到了 /docs/mcp-agents/setup,但是构建整体失败。
失败原因不是 SQLite,而是站点中存在目录分组链接:
/docs/mcp-agents
这个路径只是文档目录分组,不是实际内容页,会返回:
404 Documentation page not found
Nitro prerender 默认会因为这个 404 中断构建。
更稳妥的方案是把 Nuxt Content 的 SQLite 改成内存数据库:
export default defineNuxtConfig({
content: {
database: {
filename: ':memory:'
}
}
})
这样服务端运行时不会向文件系统写入 SQLite 文件,可以适配只读容器。
对于文档量较小的站点,内存占用通常很小。当前项目文档数量不多,SQLite 内容体积也很小,使用 :memory: 比依赖可写 /tmp 或完整 prerender 更稳定。
如果希望继续使用 prerender 解决,也可以:
/docs/mcp-agents 这类目录分组补一个真实首页文档。但这种方式依赖路由被完整覆盖,后续新增文档目录时也需要继续维护。
filename: ':memory:'。