ルーティング
Docusaurus のルーティングシステムは、1つのルートに1つのコンポーネントというシングルページアプリケーションの規約に従っています。 このセクションでは、ドキュメント、ブログ、ページといった3つのコンテンツプラグイン内のルーティングについて説明し、内部のルーティングシステムについて話を進めます。
コンテンツプラグインのルーティング
すべてのコンテンツプラグインは routeBasePath
オプションを提供しています。 プラグインがどこのルートに追加されるかを定義するものです。 デフォルトでは、ドキュメントプラグインはルートを /docs
に、ブログのプラグインは /blog
に、ページプラグインは /
になっています。 ルート構造は次のように考えることができます。
ルートはこのネストされたルート設定に照らして順に照合され、適切なマッチが見つかるまで検索が続きます。 例えば、ルートが /docs/configuration
の場合、Docusaurusはまず /docs
ブランチに入り、続いてドキュメントプラグインが作成したサブルートの中から該当するものを探します。
routeBasePath
を変更すると、サイトのルート構造が実質的に変わります。 例えば、Docs-only mode の説明で触れたように、docsプラグインの routeBasePath: '/'`\` を設定すると、docsプラグインが生成するすべてのルートから
/docs\
プレフィックスがなくなります。ただし、他のプラグインが作成する ``/blog\
のようなサブルートが存在することは妨げません。
次に、3つのプラグインがそれぞれどのように「サブルートの枠組み」を構築しているかを見てみましょう。
ページのルーティング
ページのルーティングはシンプルで、ファイルのパスがそのままURLに対応し、カスタマイズ方法はほとんどありません。 詳しくは、pagesドキュメントのルーティング解説をご覧ください。
Markdownページに使われるコンポーネントは ``@theme/MDXPage\
です。 Reactページは、そのままルートのコンポーネントとして使用されます。
ブログのルーティング
ブログは以下のルートを作成します:
- 投稿一覧のページ:
/
,/page/2
,/page/3
...- ルートは ``pageBasePath
\
オプションでカスタマイズ可能です。 - コンポーネントは
@theme/BlogListPage
です。
- ルートは ``pageBasePath
- 投稿のページ:
/2021/11/21/algolia-docsearch-migration
,/2021/05/12/announcing-docusaurus-two-beta
...- Markdown で生成されます。
- ルートは
slug
フロントマターで完全にカスタマイズできます。 - コンポーネントは
@theme/BlogPostPage
です。
- タグ一覧のページ:
/tags
- ルートは
tagsBasePath
オプションでカスタマイズできます。 - コンポーネントは
@theme/BlogTagsListPage
です。
- ルートは
- タグのページ:
/tags/adoption
,/tags/beta
...- 各投稿のフロントマターで定義されたタグから生成されます。
- ルートは常に
tagsBasePath
で定義されていますが、タグのparmalink
フィールドでサブルートをカスタマイズできます。 - コンポーネントは
@theme/BlogTagsPostsPage
です。
- アーカイブページ:
/archive
- ルートは
archiveBasePath
オプションでカスタマイズできます。 - コンポーネントは
@theme/BlogArchivePage
です。
- ルートは
ドキュメントのルーティング
Docsはネストされたルートを作成する唯一のプラグインです。 最上位では、バージョンパス(/
、/next
、/2.0.0-beta.13
など)を登録し、レイアウトやサイドバーなどのバージョンコンテキストを提供しています。 これにより、個別のドキュメント間を移動してもサイドバーの状態が保持され、ナビゲーションバーのドロップダウンからバージョンを切り替えても、同じドキュメント上に留まることができます。 使用されるコンポーネントは ``@theme/DocPage\
です。
個々のドキュメントは、ナビバーやフッター、サイドバーなどが DocPage`\` コンポーネントによって配置された残りのスペースにレンダリングされます。 例えば、このページ `<URLPath />` は、ファイル `<FilePath />` から生成されています。 使用されているコンポーネントは
@theme/DocItem\
です。
ドキュメントの slug`\` フロントマターはルートの末尾部分をカスタマイズしますが、基本のルートは常にプラグインの
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 に書き換えて解決しようとします。 - パスに他の拡張機能がある場合、Docusaurus はそれをアセットとして扱ってバンドルします。
以下のディレクトリ構成は、ファイルからURLへのマッピングをイメージしやすくするためのものです。 すべてのページで slug
のカスタマイズがないものとします。
サンプルサイトの構造
.
├── blog # blogプラグインの 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プラグインの routeBasePath は '/docs'; current バージョンは 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プラグインの routeBasePath は '/'
│ ├── index.module.css
│ ├── index.tsx # -> /
│ └── markdown-page.md # -> /markdown-page
└── versioned_docs
└── version-1.0.0 # バージョンの 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はサーバーサイドレンダリング(SSR)フレームワークのため、生成されるすべてのルートはサーバーサイドでレンダリングされ、静的なHTMLファイルとして出力されます。 もしApache2の動作に馴染みがあれば、この仕組みは理解しやすいでしょう。ブラウザが /docs/advanced/routing`\` へのリクエストを送ると、サーバーはそれを
/docs/advanced/routing/index.html\
というHTMLファイルのリクエストとして解釈し、そのファイルを返します。
/docs/advanced/routing`\` のルートは、
/docs/advanced/routing/index.html\
または ``/docs/advanced/routing.html\
のどちらかに対応する場合があります。 ホスティングプロバイダーによっては、末尾のスラッシュの有無で両者を区別し、どちらか一方のみを許容する場合があります。 詳しくは、trailing slash guideをご覧ください。
例えば、上記ディレクトリ構成のビルド出力は以下のようになります(その他のアセットや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/index.html`\` の代わりに
intro.html\
を出力します。
すべてのHTMLファイルはJSアセットを絶対URLで参照するため、正しいアセットを読み込むには baseUrl`\` の設定が必要です。 なお、
baseUrl\
は出力されるバンドルのファイル構造には影響しません。base URLはDocusaurusのルーティングシステムの一段上の階層を指します。 url`\` と
baseUrl\
の組み合わせが、実際のDocusaurusサイトの公開場所(Url)として機能します。
例えば、出力されるHTMLには以下のようなリンクが含まれます。 <link rel="preload" href="/assets/js/runtime~main.7ed5108a.js" as="script">`\`。 絶対URLはホストからのルートで解決されるため、バンドルが
https://example.com/base/`\` 配下に置かれている場合、リンクは https://example.com/assets/js/runtime~main.7ed5108a.js`\` を指してしまい、実際には存在しない場所を参照することになります。
/base/\
を base URL として指定すれば、リンクは正しく ``/base/assets/js/runtime~main.7ed5108a.js\
を指すようになります。
ローカライズされたサイトでは、ロケールが base URL の一部として含まれます。 例えば、https://docusaurus.io/zh-CN/docs/advanced/routing/`\` の場合、base URL は
/zh-CN/\
となります。
ルートの生成とアクセス
addRoute`\` ライフサイクルアクションは、ルートを生成するために使われます。 ルートツリーにルート設定の一部を登録し、ルートやコンポーネント、そしてそのコンポーネントが必要とするプロパティを指定します。 コンポーネントとプロパティはどちらもバンドラーが
require\
できるパスとして提供されます。これは、アーキテクチャ概要で説明されているように、サーバーとクライアントが一時ファイルを介してのみ通信するためです。
すべてのルートは ``.docusaurus/routes.js\
にまとめられており、デバッグプラグインのroutesパネルから確認できます。
クライアント側では、ページのルートにアクセスするための @docusaurus/router`\` が提供されています。
@docusaurus/router\
は、react-router-dom
パッケージの再エクスポートです。 例えば、useLocation`\` を使うと現在のページの[location](https://developer.mozilla.org/en-US/docs/Web/API/Location)を取得でき、
useHistory\
でhistoryオブジェクトにアクセスできます。 (機能的には似ていますが、ブラウザのAPIとは厳密には異なります。 詳しいAPIについては、React Routerのドキュメントを参照してください)
このAPIは、ブラウザ専用の ``window.location\
とは異なり、サーバーサイドレンダリング(SSR)対応となっています。
import React from 'react';
import {useLocation} from '@docusaurus/router';
export function PageRoute() {
// React RouterはSSR環境でも現在のコンポーネントのルート情報を提供します
const location = useLocation();
return (
<span>
現在のページは <code>{location.pathname}</code> です
</span>
);
}
/ja/docs/advanced/routing
ですSPA のリダイレクトを回避する
Docusaurusは、ルートの遷移をReact Routerの ``history.push()\
メソッドで行うシングルページアプリケーション(SPA)として構築されています。 この操作はクライアント側で行われます。 ただし、この方法でルート遷移が行われるためには、遷移先のURLがDocusaurusのルーターに認識されている必要があります。 そうでない場合、ルーターはそのパスを検知して404ページを表示します。
static`\` フォルダに配置したHTMLファイルはビルド時に出力先にコピーされ、そのままウェブサイト上でアクセス可能になります。ただし、これらはDocusaurusのルーティングシステムの管理外です。
pathname://\
プロトコルを用意しており、これを使うとドメイン内の別の場所へ、SPAを介さずに外部リンクのようにリダイレクトできます。
- [pathname:///pure-html](pathname:///pure-html)
pathname://`\` プロトコルは、`static` フォルダ内のコンテンツを参照するときに便利です。 例えば、Docusaurusは[すべてのMarkdown静的アセットをrequire()呼び出しに変換します](../guides/markdown-features/markdown-features-assets.mdx#static-assets)。
pathname://\
を使うと、Webpackによってハッシュ化されるのを防ぎ、通常のリンクとして扱うことができます。

[An asset from the static](pathname:///files/asset.pdf)
Docusaurusは ``pathname://\
プレフィックスを取り除くだけで、その後のコンテンツ自体は処理しません。