路由
基于文件的路由
VitePress 使用基于文件的路由,这意味着生成的 HTML 页面是从源 Markdown 文件的目录结构映射而来的。例如,给定以下目录结构:
.
├─ guide
│ ├─ getting-started.md
│ └─ index.md
├─ index.md
└─ prologue.md
生成的 HTML 页面将是:
index.md --> /index.html (accessible as /)
prologue.md --> /prologue.html
guide/index.md --> /guide/index.html (accessible as /guide/)
guide/getting-started.md --> /guide/getting-started.html
生成的 HTML 可以托管在任何可以提供静态文件的 Web 服务器上。
根目录和源目录
VitePress 项目的文件结构中有两个重要的概念:项目根目录和源目录。
项目根目录
项目根目录是 VitePress 尝试查找.vitepress
特殊目录的位置。 .vitepress
目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的保留位置。
当您从命令行运行vitepress dev
或vitepress build
时,VitePress将使用当前工作目录作为项目根目录。要将子目录指定为根目录,您需要将相对路径传递给命令。例如,如果您的 VitePress 项目位于./docs
,则应该运行vitepress dev docs
:
.
├─ docs # project root
│ ├─ .vitepress # config dir
│ ├─ getting-started.md
│ └─ index.md
└─ ...
vitepress dev docs
这将产生以下源到 HTML 的映射:
docs/index.md --> /index.html (accessible as /)
docs/getting-started.md --> /getting-started.html
源目录
源目录是 Markdown 源文件所在的位置。默认情况下,它与项目根目录相同。但是,您可以通过 srcDir
配置选项来配置它。
srcDir
选项是相对于项目根目录解析的。例如,使用 srcDir: 'src'
,您的文件结构将如下所示:
. # project root
├─ .vitepress # config dir
└─ src # source dir
├─ getting-started.md
└─ index.md
生成的源到 HTML 映射:
src/index.md --> /index.html (accessible as /)
src/getting-started.md --> /getting-started.html
页面之间的链接
在页面之间链接时可以使用绝对路径和相对路径。请注意,虽然.md
和.html
扩展名都可以使用,但最佳实践是省略文件扩展名,以便 VitePress 可以根据您的配置生成最终 URL。
<!-- Do -->
[Getting Started](./getting-started)
[Getting Started](../guide/getting-started)
<!-- Don't -->
[Getting Started](./getting-started.md)
[Getting Started](./getting-started.html)
在[资源处理](资源处理)中了解有关链接到图像等资源的更多信息。
生成干净的 URL
Server Support Required
要使用 VitePress 提供干净的 URL,需要服务器端支持。
默认情况下,VitePress 解析以.html
结尾的 URL 的入站链接。但是,某些用户可能更喜欢不带.html
扩展名的"干净 URL" - 例如,example.com/path
而不是example.com/path.html
。
某些服务器或托管平台(例如 Netlify 或 Vercel)提供将/foo
等 URL 映射到/foo.html
(如果存在)的功能,而无需重定向:
- Netlify 默认支持此功能。
- Vercel 需要在
vercel.json
中启用cleanUrls
选项。
如果您可以使用此功能,那么您还可以启用 VitePress 自己的 cleanUrls
配置选项,以便:
- 生成的页面之间的入站链接不带
.html
扩展名。 - 如果当前路径以
.html
结尾,路由器将执行客户端重定向到无扩展名路径。
但是,如果您无法使用此类支持配置服务器(例如 GitHub 页面),则必须手动求助于以下目录结构:
.
├─ getting-started
│ └─ index.md
├─ installation
│ └─ index.md
└─ index.md
路由重写
您可以自定义源目录结构和生成的页面之间的映射。当您有复杂的项目结构时,它非常有用。例如,假设您有一个包含多个包的 monorepo,并且希望将文档与源文件一起放置,如下所示:
.
├─ packages
│ ├─ pkg-a
│ │ └─ src
│ │ ├─ pkg-a-code.ts
│ │ └─ pkg-a-docs.md
│ └─ pkg-b
│ └─ src
│ ├─ pkg-b-code.ts
│ └─ pkg-b-docs.md
您希望 VitePress 页面生成如下:
packages/pkg-a/src/pkg-a-docs.md --> /pkg-a/index.html
packages/pkg-b/src/pkg-b-docs.md --> /pkg-b/index.html
您可以通过配置 rewrites
选项来实现此目的,如下所示:
// .vitepress/config.js
export default {
rewrites: {
'packages/pkg-a/src/pkg-a-docs.md': 'pkg-a/index.md',
'packages/pkg-b/src/pkg-b-docs.md': 'pkg-b/index.md'
}
}
rewrites
选项还支持动态路由参数。在上面的示例中,如果有很多包,则列出所有路径会很冗长。鉴于它们都具有相同的文件结构,您可以像这样简化配置:
export default {
rewrites: {
'packages/:pkg/src/(.*)': ':pkg/index.md'
}
}
重写路径是使用 path-to-regexp
包编译的 - 请参阅其文档以获取更高级的语法。
具有重写的相对链接
启用重写后,相对链接应基于重写的路径。例如,为了创建从 packages/pkg-a/src/pkg-a-code.md
到 packages/pkg-b/src/pkg-b-code.md
的相对链接,您应该使用:
[Link to PKG B](../pkg-b/pkg-b-code)
动态路由
您可以使用单个 Markdown 文件和动态数据生成许多页面。例如,您可以创建一个 packages/[pkg].md
文件,为项目中的每个包生成相应的页面。这里,[pkg]
段是一个路由参数,它将每个页面与其他页面区分开来。
路径加载文件
由于 VitePress 是静态站点生成器,因此必须在构建时确定可能的页面路径。因此,动态路由页面必须附有路径加载器文件。对于 packages/[pkg].md
,我们需要 packages/[pkg].paths.js
(也支持 .ts
):
.
└─ packages
├─ [pkg].md # route template
└─ [pkg].paths.js # route paths loader
路径加载器应该提供一个带有paths
方法的对象作为其默认导出。 paths
方法应该返回一个带有 params
属性的对象数组。这些对象中的每一个都会生成一个相应的页面。
给定以下paths
数组:
// packages/[pkg].paths.js
export default {
paths() {
return [
{ params: { pkg: 'foo' }},
{ params: { pkg: 'bar' }}
]
}
}
生成的 HTML 页面将是:
.
└─ packages
├─ foo.html
└─ bar.html
多个参数
动态路由可以包含多个参数:
文件结构
.
└─ packages
├─ [pkg]-[version].md
└─ [pkg]-[version].paths.js
Paths Loader
export default {
paths: () => [
{ params: { pkg: 'foo', version: '1.0.0' }},
{ params: { pkg: 'foo', version: '2.0.0' }},
{ params: { pkg: 'bar', version: '1.0.0' }},
{ params: { pkg: 'bar', version: '2.0.0' }}
]
}
输出
.
└─ packages
├─ foo-1.0.0.html
├─ foo-2.0.0.html
├─ bar-1.0.0.html
└─ bar-2.0.0.html
动态生成路径
路径加载器模块在 Node.js 中运行,并且仅在构建时执行。您可以使用本地或远程的任何数据动态生成路径数组。
从本地文件生成路径:
import fs from 'fs'
export default {
paths() {
return fs
.readdirSync('packages')
.map((pkg) => {
return { params: { pkg }}
})
}
}
从远程数据生成路径:
export default {
async paths() {
const pkgs = await (await fetch('https://my-api.com/packages')).json()
return pkgs.map((pkg) => {
return {
params: {
pkg: pkg.name,
version: pkg.version
}
}
})
}
}
访问页面中的参数
您可以使用参数将附加数据传递到每个页面。 Markdown 路由文件可以通过 $params
全局属性访问 Vue 表达式中的当前页面参数:
- package name: {{ $params.pkg }}
- version: {{ $params.version }}
您还可以通过 useData
运行时 API 访问当前页面的参数。这在 Markdown 文件和 Vue 组件中都可用:
<script setup>
import { useData } from 'vitepress'
// params is a Vue ref
const { params } = useData()
console.log(params.value)
</script>
渲染原始内容
传递到页面的参数将在客户端 JavaScript 负载中序列化,因此您应该避免在参数中传递大量数据,例如从远程 CMS 获取的原始 Markdown 或 HTML 内容。
相反,您可以使用每个路径对象上的content
属性将此类内容传递到每个页面:
export default {
async paths() {
const posts = await (await fetch('https://my-cms.com/blog-posts')).json()
return posts.map((post) => {
return {
params: { id: post.id },
content: post.content // raw Markdown or HTML
}
})
}
}
然后,使用以下特殊语法将内容呈现为 Markdown 文件本身的一部分:
<!-- @content -->