现象
构建可以完成,但预渲染阶段提示内容集合不存在或为空,文章详情页的 getStaticPaths 拿到空数组,产出 0 个页面——构建是“绿”的,内容却静默消失。
根因
Astro 7 的 Content Collections 不再自动推断目录结构,每个集合必须显式声明 loader。两个常见的静默失败点:
glob的base路径与实际内容目录不一致(比如内容在src/content/posts/而base指向了旧的src/content/blog/),loader 不会报错,只会给出空集合;- 文件的 frontmatter 不符合该集合的 schema(如日期字段类型不对、必填缺失),条目被整体丢弃。
修复:显式 loader 对齐真实目录
本项目 src/content.config.ts 中每个集合都显式声明 glob loader,且 base 与内容目录一一对应:
const posts = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/posts' }),
schema: postSchema,
});
const pitfalls = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/pitfalls' }),
schema: postSchema.extend({
severity: z.enum(['low', 'medium', 'high']).default('medium'),
}),
});
防复发:构建期三道闸
空集合最怕“静默”,所以把校验前移:
- schema 层:日期用
z.coerce.date()、必填title/description/publishedAt/tags/category,写错字段类型在 dev 就会看到 400 行错误而不是空结果; - 内容检查脚本(
scripts/check-content.mjs,挂进prebuild):统计各集合条目数、slug 冲突、relatedPosts引用完整性,坏数据直接让构建失败; - 详情渲染批测:对 sitemap 中全部文章/踩坑/项目/日志详情页断言标题与正文长度——集合又空了,批测立刻可见地失败。
验证方式
最快的自查两连:
# 1. 集合是否真的读到了条目
npx astro build 2>&1 | grep -oE "prerendered [0-9]+ pages"
# 2. 单个集合计数与内容文件数是否一致
ls src/content/posts/*.mdx | wc -l
两个数字对不上(或页面数骤降为文章数+0),优先查 base 路径与某个文件的 frontmatter 是否把整个集合带崩。