ページの流れと定義
ビルド時とリクエスト時の流れ
処理は、ビルド時とリクエスト時の2つに分かれます。
ビルド時
ビルド時には、プラグインが提供するページ種別から、静的に生成する URL を集めます。
Diagram source
flowchart LR
Plugin["プラグインのページ種別"]
Paths["公開URL"]
Params["SSGパラメータ"]
Build["静的生成"]
Plugin --> Paths
Paths --> Params
Params --> Build
たとえばプラグインが次の URL を提供していれば、その URL をSSGの生成対象にできます。
/report
リクエスト時
リクエストが届くと、共通の解決処理がページの種類を判断します。
Diagram source
flowchart TD
Request["リクエスト"]
Resolver["resolveRiebeckiteRoute"]
Request --> Resolver
Resolver --> Q{"何が一致した?"}
Q -->|"プラグインページ"| Page["プラグインページ"]
Q -->|"コンテンツ"| Content["コンテンツ"]
Q -->|"リダイレクト"| Redirect["リダイレクト"]
Q -->|"なし"| NotFound["404"]
プラグインページが見つかった場合は、その本文をサイトの HTML 文書の枠組みの中へ描画します。
Diagram source
flowchart LR
Page["プラグインページ<br/>本文とメタデータ"]
Frame["サイトのHTML文書の枠組み"]
Theme["テーマCSS"]
Client["プラグインのクライアントコード"]
Browser["完成したページ"]
Page --> Frame
Theme --> Frame
Client --> Frame
Frame --> Browser
ページの種類を定義する
ページの種類(Page Type)は、プラグインの pageTypes に定義します。
import { definePlugin } from "@riebeckite/core";
export function report() {
return definePlugin({
name: "report",
pageTypes: [
{
id: "example.report",
paths: ["/report"],
resolve: ({ pathname, manifest }) =>
pathname === "/report"
? {
type: "example.report",
pathname,
title: "Report",
body: `<p>${manifest.publicEntries.length} published entries</p>`,
}
: null,
},
],
});
}
この例では、プラグインが /report というページを提供します。ページ本文には、公開されている記事の数を表示しています。
プラグインが HonoX のコンポーネントやルートファイルを作る必要はありません。
公開済みコンテンツだけを参照する
ページ種別の resolve には PluginPageContext が渡されます。その中の PluginPageContext.manifest は、解決済みのマニフェストです。
PluginPageContext.manifest
entries には draft と scheduled も含まれるため、ページの出力には使わないでください。
公開 URL をすべて列挙する場合は publicEntries(public と unlisted)を、読者へ一覧として見せる場合は discoverableEntries(public のみ)を使います。記事ごとに分岐が必要な場合だけ、解決済みの entry.publishing を読みます。
Diagram source
flowchart LR
All["すべてのコンテンツ"]
Publish["公開境界"]
Public["publicEntries / discoverableEntries"]
Page["プラグインページ"]
All --> Publish
Publish --> Public
Public --> Page
ページ側で非公開コンテンツを独自に探して表示するのではなく、この公開境界を通してください。通常のページと同じ公開範囲を保てます。
ページ種別の識別子
各ページ種別には ID が必要です。
id: "example.report"
ID は、すべてのプラグインを通して一意でなければなりません。次のように、プラグインや用途が分かる名前空間を付けると衝突を避けやすくなります。
riebeckite.garden-explorer
example.report
example.search
公開するURL
静的なページは、paths に公開 URL を指定します。
paths: ["/report"]
複数のページを提供することもできます。
paths: [
"/report",
"/report/archive",
]
動的ページを静的生成する場合は、SSG の URL を manifest.publicEntries から導出します。ファイルシステムを独自に走査して URL を作るのではなく、Content System が解決した公開状態を利用してください。
同じURLに複数のページが一致する場合
複数のページ種別が同じ URL に一致することがあります。その場合は priority で優先順位を決めます。
Diagram source
flowchart TD
Path["/report"]
A["ページ種別A<br/>priority: 10"]
B["ページ種別B<br/>priority: 20"]
Path --> A
Path --> B
A --> Compare{"priorityを比較"}
B --> Compare
Compare -->|"Bが高い"| Result["ページ種別B"]
最も高い priority を持つページ種別が選ばれます。
ただし、最大の priority を持つページ種別が複数一致した場合は、どちらかを暗黙に選びません。
Diagram source
flowchart TD
Match["複数のページ種別が一致"]
Priority{"最大のpriorityは1つ?"}
Match --> Priority
Priority -->|"はい"| Resolve["そのページ種別を使う"]
Priority -->|"いいえ"| Error["競合エラー"]
競合をエラーにすることで、プラグインの登録順などによって結果が変わることを防ぎます。