特殊用途のページ

テーマは、theme.pagesDir を通じて独自のページを同梱できます。これらのテーマページはユーザーページと同様のルーティングルールで処理されますが、ルートが重複した場合は常にユーザー側のページが優先されます。

主な活用例:

テーマからページを提供する方法

theme/index.js でディレクトリを指定します。

export default () => ({
	theme: {
		root: '.',
		pagesDir: './pages'
	}
})

theme/pages/ 内の構成例:

pages/
  index.mdx
  menu.mdx
  friends.mdx
  contact.mdx
  404.mdx

フロントマターによるレイアウトの切り替え

最も柔軟な方法は、フロントマターに layout プロパティを定義し、テンプレート内で条件分岐を行う手法です。

例: menu.mdx

---
title: Menu
layout: menu
hidden: true
---

# Menu

このページは専用のレイアウトでレンダリングされます。

テンプレートでの実装例:

const MenuLayout = ({ ctx, PageContent }) => (
	<div class="menu-layout">
		<h1>{ctx.page.title}</h1>
		<PageContent />
	</div>
)

const DocLayout = ({ ctx, PageContent }) => (
	<div class="doc-layout">
		<aside>{/* ナビゲーション */}</aside>
		<main>
			<PageContent />
		</main>
	</div>
)

export default function PageTemplate({ PageContent, ExtraHead, ctx }) {
	const layout = ctx.page.frontmatter?.layout
	return (
		<>
			<html>
				<head>
					<ExtraHead />
					<title>{ctx.page.title || ctx.site.name}</title>
				</head>
				<body>
					{layout === 'menu' ? (
						<MenuLayout ctx={ctx} PageContent={PageContent} />
					) : (
						<DocLayout ctx={ctx} PageContent={PageContent} />
					)}
				</body>
			</html>
		</>
	)
}

ルートパスによる条件分岐

特定のパスに対してルールを固定したい場合は、ルートパスによる判定も有効です。

const route = ctx.page.routePath
if (route === '/menu') { /* ... */ }

補足: ディレクトリのインデックスページの場合、routePath の末尾には / が付与されます(例: /guide/)。

インタラクティブなページの実装(フォームなど)

お問い合わせフォームなどの複雑なインタラクションが必要なページでは、ページ自体のレンダリングは通常通り行い、テーマ側の components/.client サフィックス付きのコンポーネントを用意して本文内で呼び出す構成が推奨されます。

代替案: .html ファイルによる実装

特殊用途のページは必ずしも MDX である必要はありません。テーマの pagesDir に直接 .html ファイルを配置することも可能です。

これらのファイルもビルドプロセスに含まれ、Vite による最適化と theme.template によるラップが適用されます。テンプレート側でファイル拡張子や特定のフロントマターを判定し、サイドバーやフッターを除去した独立したレイアウトを適用するのが一般的な手法です。

一般的な判定パターン:

パス解決に関する注意点

theme.sources で定義された URL や public/ 配下の静的ファイルは、ビルド時に自動的に解決されるため、通常は withBase() を使用する必要はありません。ただし、JavaScript 内でパスを動的に生成する場合の安全策として withBase('/...') を利用できます。 drum