zfb
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

ページモジュールのエクスポート

zfb がページモジュールから読み取る named export のリファレンス。

pages/ 配下のすべてのファイルは、ページコンポーネントを default export する必要があります。zfb はそれに加えて、ページモジュールからいくつかの named export を読み取り、どの URL が存在するか、コンポーネントへどの props を渡すか、ルートを prerender するか、どのレスポンスメタデータを使うかを決定します。

export default function Page(props: Record<string, unknown>) {
  return <main>{/* ... */}</main>;
}

出荷されている named export は、paths()getStaticProps()prerendercontentTypeheadings です。

Warning

export const meta は、出荷済みのページモジュール API ではありません。head タグ、レイアウト選択、Open Graph データ、ページメタデータのために依存しないでください。head マークアップはコンポーネント / レイアウトコードに置くか、paths() / getStaticProps() の props 経由でデータを渡してください。

paths()

export function paths():
  | Array<{ params: Record<string, string | string[]>; props?: Record<string, unknown> }>
  | Promise<Array<{ params: Record<string, string | string[]>; props?: Record<string, unknown> }>>;

pages/blog/[slug].tsxpages/docs/[...slug].tsxpages/docs/[[...slug]].tsx のような動的ルートは、paths() を使って具体的な URL を列挙します。各エントリは、ルート内のすべての動的セグメントに対応するキーを持つ params オブジェクトを含む必要があります。任意の propsparams とともに、ページコンポーネントのトップレベル props へ展開されます。

SSG ルートでは、zfb はまずリテラルな paths() 結果を静的に抽出しようとします。リテラルではない関数は、ビルド中にバンドル済みランタイムを通じて評価されます。prerender = false の動的ルートはリクエスト時に配信されるため、ビルド時の具体的な URL 一覧は不要です。

import { getCollection } from "@takazudo/zfb/content";

export async function paths() {
  const posts = getCollection<{ title: string }>("blog");
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { title: post.data.title },
  }));
}

export default function PostPage({
  params,
  title,
}: {
  params: { slug: string };
  title: string;
}) {
  return <h1>{title}</h1>;
}

getStaticProps()

export function getStaticProps():
  | { props: Record<string, unknown> }
  | Promise<{ props: Record<string, unknown> }>;

静的ルートは getStaticProps() をエクスポートして、ページコンポーネントがレンダリングされる前に props を計算できます。これは静的な非動的ルート向けです。動的ルートでは、代わりに paths() からエントリごとの props を返してください。

import { getCollection } from "@takazudo/zfb/content";

export function getStaticProps() {
  const posts = getCollection<{ title: string }>("blog");
  return {
    props: {
      postCount: posts.length,
      latestTitle: posts.at(-1)?.data.title ?? "No posts",
    },
  };
}

export default function BlogIndex({
  postCount,
  latestTitle,
}: {
  postCount: number;
  latestTitle: string;
}) {
  return (
    <main>
      <h1>Blog</h1>
      <p>{postCount} posts</p>
      <p>Latest: {latestTitle}</p>
    </main>
  );
}

prerender

export const prerender: boolean;

ルートはデフォルトでディスクへ prerender されます。ページを SSG から外して、代わりにランタイム SSR アダプタ経由で配信するには、prerender = false を設定します。SSR 対応アダプタのないプロジェクトに prerender = false ルートが含まれている場合は、早い段階で失敗します。

静的 extractor が尊重するのはリテラルの boolean export だけです。計算された値はデフォルト(true)として扱われます。

export const prerender = false;

export default function PreviewPage() {
  return <h1>This route is rendered at request time</h1>;
}

contentType

export const contentType: string;

contentType は TSX ページのレスポンス Content-Type を上書きします。HTML 以外のページや、ファイル名拡張子だけでは足りない場合に使います。省略すると、zfb は出力拡張子から型を導出し、最後は text/html; charset=utf-8 にフォールバックします。

export const contentType = "application/xml";

export default function Sitemap() {
  return (
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>https://example.com/</loc>
      </url>
    </urlset>
  );
}

headings

export const headings: readonly Array<{
  depth: number;
  slug: string;
  text: string;
}>;

MDX コンパイルは、コンパイル済みのすべての Markdown / MDX モジュールに headings export を出力します。これはソース内の見出しから導出される、文書順の目次です。空の文書でも [] を export するため、利用側は無条件に import できます。

通常、TSX ページで headings を手書きすることはありません。MDX モジュールから import するか、フレームワークレベルの UI を構築するときにページモジュール namespace から読み取ってください。

import DocsPage, { headings } from "../content/docs/intro.mdx";

export function getStaticProps() {
  return {
    props: {
      tableOfContents: headings.filter((heading) => heading.depth <= 3),
    },
  };
}

export default function IntroPage({
  tableOfContents,
}: {
  tableOfContents: typeof headings;
}) {
  return (
    <main>
      <nav>
        {tableOfContents.map((heading) => (
          <a href={`#${heading.slug}`}>{heading.text}</a>
        ))}
      </nav>
      <DocsPage />
    </main>
  );
}

Revision History

作成更新