Color mode

ページの流れと定義

ビルド時とリクエスト時の流れ

処理は、ビルド時とリクエスト時の2つに分かれます。

ビルド時

ビルド時には、プラグインが提供するページ種別から、静的に生成する URL を集めます。

Diagram source
text
flowchart LR
    Plugin["プラグインのページ種別"]
    Paths["公開URL"]
    Params["SSGパラメータ"]
    Build["静的生成"]
 
    Plugin --> Paths
    Paths --> Params
    Params --> Build

たとえばプラグインが次の URL を提供していれば、その URL をSSGの生成対象にできます。

text
/report

リクエスト時

リクエストが届くと、共通の解決処理がページの種類を判断します。

Diagram source
text
flowchart TD
    Request["リクエスト"]
    Resolver["resolveRiebeckiteRoute"]
 
    Request --> Resolver
 
    Resolver --> Q{"何が一致した?"}
 
    Q -->|"プラグインページ"| Page["プラグインページ"]
    Q -->|"コンテンツ"| Content["コンテンツ"]
    Q -->|"リダイレクト"| Redirect["リダイレクト"]
    Q -->|"なし"| NotFound["404"]

プラグインページが見つかった場合は、その本文をサイトの HTML 文書の枠組みの中へ描画します。

Diagram source
text
flowchart LR
    Page["プラグインページ<br/>本文とメタデータ"]
    Frame["サイトのHTML文書の枠組み"]
    Theme["テーマCSS"]
    Client["プラグインのクライアントコード"]
    Browser["完成したページ"]
 
    Page --> Frame
    Theme --> Frame
    Client --> Frame
    Frame --> Browser

ページの種類を定義する

ページの種類(Page Type)は、プラグインの pageTypes に定義します。

ts
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 は、解決済みのマニフェストです。

ts
PluginPageContext.manifest

entries には draft と scheduled も含まれるため、ページの出力には使わないでください。

公開 URL をすべて列挙する場合は publicEntries(public と unlisted)を、読者へ一覧として見せる場合は discoverableEntries(public のみ)を使います。記事ごとに分岐が必要な場合だけ、解決済みの entry.publishing を読みます。

Diagram source
text
flowchart LR
    All["すべてのコンテンツ"]
    Publish["公開境界"]
    Public["publicEntries / discoverableEntries"]
    Page["プラグインページ"]
 
    All --> Publish
    Publish --> Public
    Public --> Page

ページ側で非公開コンテンツを独自に探して表示するのではなく、この公開境界を通してください。通常のページと同じ公開範囲を保てます。

ページ種別の識別子

各ページ種別には ID が必要です。

ts
id: "example.report"

ID は、すべてのプラグインを通して一意でなければなりません。次のように、プラグインや用途が分かる名前空間を付けると衝突を避けやすくなります。

text
riebeckite.garden-explorer
example.report
example.search

公開するURL

静的なページは、paths に公開 URL を指定します。

ts
paths: ["/report"]

複数のページを提供することもできます。

ts
paths: [
  "/report",
  "/report/archive",
]

動的ページを静的生成する場合は、SSG の URL を manifest.publicEntries から導出します。ファイルシステムを独自に走査して URL を作るのではなく、Content System が解決した公開状態を利用してください。

同じURLに複数のページが一致する場合

複数のページ種別が同じ URL に一致することがあります。その場合は priority で優先順位を決めます。

Diagram source
text
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
text
flowchart TD
    Match["複数のページ種別が一致"]
    Priority{"最大のpriorityは1つ?"}
 
    Match --> Priority
 
    Priority -->|"はい"| Resolve["そのページ種別を使う"]
    Priority -->|"いいえ"| Error["競合エラー"]

競合をエラーにすることで、プラグインの登録順などによって結果が変わることを防ぎます。

Local Graph

Nearby Notes