Skip to content

路由

基于文件的路由

VitePress 使用基于文件的路由,这意味着生成的 HTML 页面是从源 Markdown 文件的目录结构映射而来的。例如,给定以下目录结构:

docs/
├─ guide/
│  ├─ getting-started.md
│  └─ index.md
├─ index.md
└─ prologue.md

生成的 HTML 页面将是:

index.md                 -->  /index.html (可以通过 / 访问)
prologue.md              -->  /prologue.html
guide/index.md           -->  /guide/index.html (可以通过 /guide/ 访问)
guide/getting-started.md -->  /guide/getting-started.html

生成的 HTML 可以托管在任何能够提供静态文件的 Web 服务器上。

根目录和源目录

VitePress 项目中有两个重要的概念:项目根目录源目录

项目根目录

项目根目录是 VitePress 将尝试寻找 .vitepress 特殊目录的地方。.vitepress 目录是 VitePress 配置文件、开发服务器缓存、构建输出和可选主题自定义代码的预留位置。

当你从命令行运行 vitepress devvitepress build 时,VitePress 将使用当前工作目录作为项目根目录。要将子目录指定为根目录,你需要将相对路径传递给命令:

vitepress dev docs

这将使用 ./docs 作为项目根目录,并寻找 ./docs/.vitepress 配置目录。

源目录

源目录是 Markdown 源文件所在的位置。默认情况下,它与项目根目录相同。但是,你可以通过 srcDir 配置选项对其进行配置。

srcDir 选项是相对于项目根目录解析的。例如,使用 srcDir: 'src',你的文件结构将如下所示:

.                          # 项目根目录
├─ .vitepress              # 配置目录
└─ src                     # 源目录
   ├─ getting-started.md
   └─ index.md

生成的源文件到 HTML 的映射:

src/index.md            -->  /index.html
src/getting-started.md  -->  /getting-started.html

页面间链接

你可以在页面之间使用相对路径进行链接。请注意,虽然你可以省略 .md 扩展名,但如果你引用的页面在不同的目录中,则必须包含目录路径:

md
<!-- 做 -->
[入门指南](./getting-started)
[入门指南](../guide/getting-started)

<!-- 不要做 -->
[入门指南](../getting-started)
[入门指南](getting-started.html)

另请参阅资源处理以了解如何链接到静态资源。

链接到非 VitePress 页面

如果你想链接到站点内不是由 VitePress 生成的页面,则需要使用完整的 URL(在新窗口中打开)或明确指定目标:

md
[Link to pure.html](../../pure.html){target="_self"}

生成简洁的 URL

服务器支持必需

要提供简洁的 URL,需要服务器端支持。

默认情况下,VitePress 将传入的 URL 解析为以 .html 结尾。但是,一些用户可能更喜欢没有 .html 扩展名的"简洁 URL"——例如,example.com/path 而不是 example.com/path.html

一些服务器或托管平台(例如 Netlify、Vercel、GitHub Pages)提供了将 /foo 这样的 URL 映射到 /foo.html 的能力(如果存在),而无需重定向:

如果此功能对你可用,你还可以启用 VitePress 自己的 cleanUrls 配置选项,以便:

  • 页面之间的内部链接生成时不带 .html 扩展名
  • 如果当前路径以 .html 结尾,路由器将执行客户端重定向到无扩展名路径

但是,如果你无法为服务器配置此类支持,则必须手动使用以下目录结构:

.
├─ 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 选项来实现此目的:

ts
// .vitepress/config.ts
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 选项还支持动态路由参数。在上面的示例中,如果你有很多包,列出每个包会很冗长。给定上面的文件结构,你可以简化配置:

ts
export default {
  rewrites: {
    'packages/:pkg/src/(.*)': ':pkg/index.md'
  }
}

重写路径使用 path-to-regexp 包编译——有关更高级的语法,请参阅其文档

重写时的相对链接

启用重写时,相对链接应基于重写的路径。例如,要从 packages/pkg-a/src/pkg-a-docs.md 创建到 packages/pkg-b/src/pkg-b-docs.md 的相对链接,你应该使用:

md
[Link to PKG B](../pkg-b/index)

动态路由

你可以使用单个 Markdown 文件和动态数据生成许多页面。例如,你可以创建一个 packages/[pkg].md 文件,为项目中的每个包生成相应的页面。这里,[pkg] 段是一个路由参数,用于区分每个页面。

路径加载文件

由于 VitePress 是静态站点生成器,可能的页面路径必须在构建时确定。因此,动态路由页面必须附带一个路径加载文件。对于 packages/[pkg].md,我们需要 packages/[pkg].paths.js(也支持 .ts):

js
// packages/[pkg].paths.js
export default {
  paths() {
    return [
      { params: { pkg: 'pkg-a' }},
      { params: { pkg: 'pkg-b' }}
    ]
  }
}

paths 函数应该返回一个具有 params 属性的对象数组。每个对象都将生成相应的页面。

所以如果我们有以下路径:

js
export default {
  paths() {
    return [
      { params: { pkg: 'pkg-a' }},
      { params: { pkg: 'pkg-b' }}
    ]
  }
}

那么生成的 HTML 页面将是:

/packages/pkg-a.html
/packages/pkg-b.html

多个参数

动态路由可以包含多个参数:

文件结构

─ packages
   └─ [pkg]
      └─ [version]
         └─ index.md

路径文件

js
export default {
  paths: () => [
    { params: { pkg: 'pkg-a', version: '1.0.0' }},
    { params: { pkg: 'pkg-a', version: '2.0.0' }},
    { params: { pkg: 'pkg-b', version: '1.0.0' }},
    { params: { pkg: 'pkg-b', version: '2.0.0' }}
  ]
}

生成的页面

/packages/pkg-a/1.0.0/index.html
/packages/pkg-a/2.0.0/index.html
/packages/pkg-b/1.0.0/index.html
/packages/pkg-b/2.0.0/index.html

动态生成路径

路径加载模块在 Node.js 中运行,只在构建时执行。你可以使用任何数据(本地或远程)动态生成路径数组。

从本地文件生成路径:

js
import fs from 'fs'

export default {
  paths() {
    return fs
      .readdirSync('packages')
      .map((pkg) => {
        return { params: { pkg }}
      })
  }
}

从远程数据生成路径:

js
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 表达式中访问当前页面参数:

md
- package name: {{ $params.pkg }}
- version: {{ $params.version }}

你还可以通过 useData 运行时 API 访问当前页面的参数。这在 Markdown 文件和 Vue 组件中都有效:

vue
<script setup>
import { useData } from 'vitepress'

const { params } = useData()

console.log(params.pkg)
</script>

渲染原始内容

传递给页面的参数将在客户端 JavaScript 有效负载中序列化,因此你应该避免在参数中传递重数据,例如在远程 CMS 中获取的原始 Markdown 或 HTML 内容。

相反,你可以使用每个路径对象上的 content 属性将此类内容传递给每个页面:

js
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, /* 其他 url 参数 */ },
        content: post.content // 原始 Markdown 或 HTML
      }
    })
  }
}

然后,使用以下特殊语法将内容渲染为页面本身的一部分:

md
# {{ $params.id }}

<Content />

<Content /> 是一个内置组件,它将渲染路径对象的 content 属性中包含的原始内容。

vitepress开发指南