页面与地址
用 minidocs 的 glob 加载的集合里,每个文件都是一个页面。这一页讲文件怎样变成页面 id 和地址,以及渲染它们的路由文件放在哪里。
页面 id
页面 id 是文件相对于 glob 的 base 的路径,去掉扩展名。目录里的 index 代表目录本身:
| 文件 | 页面 id |
|---|---|
index.mdx |
index |
hello.mdx |
hello |
guides/index.mdx |
guides |
guides/sidebar.mdx |
guides/sidebar |
文档树的 page()、下文的 toHref() 这些接收页面 id 的地方都有补全,写错的 id 是类型错误。
括号目录
名字带括号的目录,比如 (basics),只用来整理文件,不出现在页面 id 里:
| 文件 | 页面 id |
|---|---|
(start)/index.mdx |
index |
(start)/install.mdx |
install |
guides/(basics)/links.mdx |
guides/links |
多语言站点
在 Astro 配置里设置了 i18n 时,集合的第一级目录是语言,比如 zh/hello.mdx 和 en/hello.mdx。页面 id 不含语言,两者都是 hello。
排除页面
草稿这类不想发布的页面,用 glob 的 filter 排除:
glob({
base: './src/content/docs',
pattern: '**/*.{md,mdx}',
prefix: 'docs',
filter: (entry) => !entry.data.draft,
});
filter 收到的是集合里的条目,已经过 schema 校验,entry.data 就是 frontmatter。被排除的页面不会进入集合:补全里没有它的 id,链接到它会让构建失败。想在开发服务器里预览草稿、只在构建时排除,就写成 import.meta.env.DEV || !entry.data.draft。
在 filter 里排除,而不是 getCollection 之后
getCollection('docs').filter(...) 只影响你拿到的条目,类型和链接检查仍然认为这些页面存在。
地址
页面的地址由三部分组成:语言、集合的 prefix、页面 id。prefix 是 docs 时:
| 页面 id | 地址 | 多语言站点上的 en |
|---|---|---|
index |
/docs/ |
/en/docs/ |
hello |
/docs/hello/ |
/en/docs/hello/ |
guides/sidebar |
/docs/guides/sidebar/ |
/en/docs/guides/sidebar/ |
不设 prefix 时,页面放在站点根路径下。多语言站点上,语言段按 Astro 的 i18n 配置决定,默认语言通常不带语言段。base 和末尾斜杠也跟随 Astro 的配置。
在代码里拿到一个页面的链接,用 toHref:
toHref('docs', 'guides/sidebar'); // '/docs/guides/sidebar/'
toHref('docs', 'guides/sidebar', 'en'); // 多语言站点要传语言
第一个参数是集合名。在正文里链接到另一个页面,直接写文件路径,见正文里的链接。
路由文件
渲染一个集合的路由文件,放在 prefix 对应的文件夹里,文件结构和地址结构一致:
| 站点 | 路由文件 |
|---|---|
| 单语言 | src/pages/docs/[...slug].astro |
| 多语言 | src/pages/[...locale]/docs/[...slug].astro |
listPages 返回的每个页面都带着它的路由参数 page.params,直接交给 getStaticPaths:
export function getStaticPaths() {
return pages.map((page) => ({ params: page.params, props: page }));
}
单语言站点的参数是 { slug },多语言站点是 { locale, slug }。集合首页(index)的 slug 是 undefined,默认语言不带前缀时 locale 也是 undefined。
路由文件不在 prefix 对应的文件夹里时,页面会生成到错误的地址。构建会失败,并列出没有生成的页面。