路由
Docusaurus 的路由系统遵循单页应用约定:一个路由,一个组件。在本节中,我们将首先讨论三个内容插件(文档、博客和页面)中的路由,然后深入讨论底层路由系统。
内容插件中的路由
每个内容插件都提供一个 routeBasePath
选项。它定义了插件将其路由附加到的位置。默认情况下,文档插件将其路由放在 /docs
下;博客插件放在 /blog
下;页面插件放在 /
下。您可以将路由结构视为:
任何路由都将与此嵌套路由配置进行匹配,直到找到一个良好匹配。例如,当给定路由 /docs/configuration
时,Docusaurus 首先进入 /docs
分支,然后在其由文档插件创建的子路由中进行搜索。
更改 routeBasePath
可以有效地改变您站点的路由结构。例如,在仅文档模式中,我们提到为文档配置 routeBasePath: '/'
意味着文档插件创建的所有路由将没有 /docs
前缀,但这并不妨碍您拥有由其他插件创建的更多子路由,例如 /blog
。
接下来,我们来看看这三个插件如何构建它们自己的“子路由框”。
页面路由
页面路由很简单:文件路径直接映射到 URL,没有其他自定义方式。有关更多信息,请参阅页面文档。
用于 Markdown 页面的组件是 @theme/MDXPage
。React 页面直接用作路由的组件。
博客路由
博客创建以下路由
- 文章列表页:
/
、/page/2
、/page/3
...- 此路由可通过
pageBasePath
选项自定义。 - 组件是
@theme/BlogListPage
。
- 此路由可通过
- 文章页:
/2021/11/21/algolia-docsearch-migration
、/2021/05/12/announcing-docusaurus-two-beta
...- 从每篇 Markdown 文章生成。
- 路由可通过
slug
front matter 完全自定义。 - 组件是
@theme/BlogPostPage
。
- 标签列表页:
/tags
- 此路由可通过
tagsBasePath
选项自定义。 - 组件是
@theme/BlogTagsListPage
。
- 此路由可通过
- 标签页:
/tags/adoption
、/tags/beta
...- 通过每篇文章的 front matter 中定义的标签生成。
- 路由总是以
tagsBasePath
中定义的基础路径为准,但子路由可通过标签的permalink
字段自定义。 - 组件是
@theme/BlogTagsPostsPage
。
- 归档页:
/archive
- 此路由可通过
archiveBasePath
选项自定义。 - 组件是
@theme/BlogArchivePage
。
- 此路由可通过
文档路由
文档是唯一创建嵌套路由的插件。在顶部,它注册了版本路径:/
、/next
、/2.0.0-beta.13
... 它们提供了版本上下文,包括布局和侧边栏。这确保了在不同文档之间切换时,侧边栏的状态得以保留,并且您可以通过导航栏下拉菜单在不同版本之间切换,同时停留在同一文档上。使用的组件是 @theme/DocPage
。
在导航栏、页脚、侧边栏等都由 DocPage
组件提供后,单个文档将在剩余空间中渲染。例如,此页面 /docs/advanced/routing
是从文件 ./versioned_docs/version-3.8.1/advanced/routing.md
生成的。使用的组件是 @theme/DocItem
。
文档的 slug
front matter 自定义了路由的最后一部分,但基础路由始终由插件的 routeBasePath
和版本的 path
定义。
文件路径和 URL 路径
在整个文档中,我们始终力求明确我们是在谈论文件路径还是 URL 路径。内容插件通常将文件路径直接映射到 URL 路径,例如,./docs/advanced/routing.md
将变为 /docs/advanced/routing
。但是,使用 slug
,您可以使 URL 完全与文件结构解耦。
在 Markdown 中编写链接时,您可能指的是文件路径或URL 路径,Docusaurus 将使用多种启发式方法来确定。
- 如果路径带有
@site
前缀,它总是一个资产文件路径。 - 如果路径带有
http(s)://
前缀,它总是一个 URL 路径。 - 如果路径没有扩展名,它是一个 URL 路径。例如,URL 为
/docs/advanced/routing
的页面上的链接[page](../plugins)
将链接到/docs/plugins
。Docusaurus 只会在构建您的站点时(当它知道完整的路由结构时)检测到断开的链接,但不会对文件的存在做出任何假设。这与在 JSX 文件中写入<a href="../plugins">page</a>
完全等效。 - 如果路径带有
.md(x)
扩展名,Docusaurus 将尝试将该 Markdown 文件解析为 URL,并用 URL 路径替换文件路径。 - 如果路径带有任何其他扩展名,Docusaurus 会将其视为资产并进行打包。
以下目录结构可能有助于您可视化此文件 → URL 映射。假设在任何页面中都没有 slug 自定义。
示例站点结构
.
├── blog # blog plugin has routeBasePath: '/blog'
│ ├── 2019-05-28-first-blog-post.md # -> /blog/2019/05/28/first-blog-post
│ ├── 2019-05-29-long-blog-post.md # -> /blog/2019/05/29/long-blog-post
│ ├── 2021-08-01-mdx-blog-post.mdx # -> /blog/2021/08/01/mdx-blog-post
│ └── 2021-08-26-welcome
│ ├── docusaurus-plushie-banner.jpeg
│ └── index.md # -> /blog/2021/08/26/welcome
├── docs # docs plugin has routeBasePath: '/docs'; current version has base path '/'
│ ├── intro.md # -> /docs/intro
│ ├── tutorial-basics
│ │ ├── _category_.json
│ │ ├── congratulations.md # -> /docs/tutorial-basics/congratulations
│ │ └── markdown-features.mdx # -> /docs/tutorial-basics/markdown-features
│ └── tutorial-extras
│ ├── _category_.json
│ ├── manage-docs-versions.md # -> /docs/tutorial-extras/manage-docs-versions
│ └── translate-your-site.md # -> /docs/tutorial-extras/translate-your-site
├── src
│ └── pages # pages plugin has routeBasePath: '/'
│ ├── index.module.css
│ ├── index.tsx # -> /
│ └── markdown-page.md # -> /markdown-page
└── versioned_docs
└── version-1.0.0 # version has base path '/1.0.0'
├── intro.md # -> /docs/1.0.0/intro
├── tutorial-basics
│ ├── _category_.json
│ ├── congratulations.md # -> /docs/1.0.0/tutorial-basics/congratulations
│ └── markdown-features.mdx # -> /docs/1.0.0/tutorial-basics/markdown-features
└── tutorial-extras
├── _category_.json
├── manage-docs-versions.md # -> /docs/1.0.0/tutorial-extras/manage-docs-versions
└── translate-your-site.md # -> /docs/1.0.0/tutorial-extras/translate-your-site
内容插件就说到这里。让我们退一步,总体讨论一下路由在 Docusaurus 应用中是如何工作的。
路由变为 HTML 文件
由于 Docusaurus 是一个服务器端渲染框架,所有生成的路由都将服务器端渲染成静态 HTML 文件。如果您熟悉像Apache2这样的 HTTP 服务器的行为,您就会明白这是如何完成的:当浏览器向路由 /docs/advanced/routing
发送请求时,服务器将其解释为对 HTML 文件 /docs/advanced/routing/index.html
的请求,并返回该文件。
/docs/advanced/routing
路由可以对应 /docs/advanced/routing/index.html
或 /docs/advanced/routing.html
。一些托管服务提供商通过尾部斜杠的存在来区分它们,并且可能容忍或不容忍另一种形式。在尾部斜杠指南中阅读更多信息。
例如,上述目录的构建输出是(忽略其他资产和 JS 包)
上述工作空间的输出
build
├── 404.html # /404/
├── blog
│ ├── archive
│ │ └── index.html # /blog/archive/
│ ├── first-blog-post
│ │ └── index.html # /blog/first-blog-post/
│ ├── index.html # /blog/
│ ├── long-blog-post
│ │ └── index.html # /blog/long-blog-post/
│ ├── mdx-blog-post
│ │ └── index.html # /blog/mdx-blog-post/
│ ├── tags
│ │ ├── docusaurus
│ │ │ └── index.html # /blog/tags/docusaurus/
│ │ ├── hola
│ │ │ └── index.html # /blog/tags/hola/
│ │ └── index.html # /blog/tags/
│ └── welcome
│ └── index.html # /blog/welcome/
├── docs
│ ├── 1.0.0
│ │ ├── intro
│ │ │ └── index.html # /docs/1.0.0/intro/
│ │ ├── tutorial-basics
│ │ │ ├── congratulations
│ │ │ │ └── index.html # /docs/1.0.0/tutorial-basics/congratulations/
│ │ │ └── markdown-features
│ │ │ └── index.html # /docs/1.0.0/tutorial-basics/markdown-features/
│ │ └── tutorial-extras
│ │ ├── manage-docs-versions
│ │ │ └── index.html # /docs/1.0.0/tutorial-extras/manage-docs-versions/
│ │ └── translate-your-site
│ │ └── index.html # /docs/1.0.0/tutorial-extras/translate-your-site/
│ ├── intro
│ │ └── index.html # /docs/1.0.0/intro/
│ ├── tutorial-basics
│ │ ├── congratulations
│ │ │ └── index.html # /docs/tutorial-basics/congratulations/
│ │ └── markdown-features
│ │ └── index.html # /docs/tutorial-basics/markdown-features/
│ └── tutorial-extras
│ ├── manage-docs-versions
│ │ └── index.html # /docs/tutorial-extras/manage-docs-versions/
│ └── translate-your-site
│ └── index.html # /docs/tutorial-extras/translate-your-site/
├── index.html # /
└── markdown-page
└── index.html # /markdown-page/
如果 trailingSlash
设置为 false
,构建将发出 intro.html
而不是 intro/index.html
。
所有 HTML 文件都将使用绝对 URL 引用其 JS 资产,因此为了定位正确的资产,您必须配置 baseUrl
字段。请注意,baseUrl
不影响发出的包的文件结构:基础 URL 比 Docusaurus 路由系统高一个级别。您可以将 url
和 baseUrl
的聚合视为您的 Docusaurus 站点的实际位置。
例如,发出的 HTML 将包含类似 <link rel="preload" href="#runtime~main.7ed5108a.js" as="script">
的链接。由于绝对 URL 是从主机解析的,如果包放置在路径 https://example.com/base/
下,链接将指向 https://example.com#runtime~main.7ed5108a.js
,这是不存在的。通过将 /base/
指定为基础 URL,链接将正确指向 /base#runtime~main.7ed5108a.js
。
本地化站点也将语言环境作为基础 URL 的一部分。例如,https://docusaurus.org.cn/docs/advanced/routing/
的基础 URL 为 /
。
生成和访问路由
addRoute
生命周期操作用于生成路由。它将一段路由配置注册到路由树中,提供一个路由、一个组件以及组件所需的 props。props 和组件都作为路径提供给打包器进行 require
,因为如架构概述中所述,服务器和客户端只通过临时文件通信。
所有路由都聚合在 .docusaurus/routes.js
中,您可以使用调试插件的路由面板查看。
在客户端,我们提供 @docusaurus/router
来访问页面的路由。@docusaurus/router
是 react-router-dom
包的重新导出。例如,您可以使用 useLocation
获取当前页面的位置,并使用 useHistory
访问history 对象。(它们与浏览器 API 不同,但功能相似。有关具体 API,请参阅 React Router 文档。)
此 API 是SSR 安全的,与仅限浏览器的 window.location
不同。
import React from 'react';
import {useLocation} from '@docusaurus/router';
export function PageRoute() {
// React router provides the current component's route, even in SSR
const location = useLocation();
return (
<span>
We are currently on <code>{location.pathname}</code>
</span>
);
}
/docs/advanced/routing
跳出 SPA 重定向
Docusaurus 构建一个单页应用 (SPA),其中路由转换通过 React 路由器的 history.push()
方法完成。此操作在客户端完成。但是,以这种方式发生路由转换的前提是目标 URL 为我们的路由器所知。否则,路由器会捕获此路径并显示 404 页面。
如果您将一些 HTML 页面放在 static
文件夹下,它们将被复制到构建输出中,从而成为您网站的一部分,但它们不属于 Docusaurus 路由系统。我们提供一个 pathname://
协议,允许您以非 SPA 方式重定向到域的另一部分,就好像此路由是一个外部链接一样。
- [pathname:///pure-html](pathname:///pure-html)
pathname://
协议对于引用静态文件夹中的任何内容都很有用。例如,Docusaurus 会将所有 Markdown 静态资产转换为 require() 调用。您可以使用 pathname://
使其保持为常规链接,而不是被 Webpack 散列。

[An asset from the static](pathname:///files/asset.pdf)
Docusaurus 只会剥离 pathname://
前缀,而不处理内容。