AstroでMarkdown記事の詳細ページをgetStaticPathsで生成する

AstroでMarkdown記事の詳細ページを作る場合、getStaticPaths() を使ってURLを生成します。

src/content/posts/foo.md/posts/foo/ として出したい、というケースです。

Astro公式の動的ルーティングにも、getStaticPaths() を使う流れが載っています。

https://docs.astro.build/en/guides/routing/#dynamic-routes

ファイル構成

src/
├── content/
│   └── posts/
│       └── first-post.md
└── pages/
    └── posts/
        └── [...slug].astro

[...slug].astro で、Markdownファイルごとのページを生成します。

getStaticPathsを書く

---
import { getCollection, render } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('posts', ({ data }) => !data.draft);

  return posts.map((post) => ({
    params: { slug: post.id.replace(/\.mdx?$/, '') },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

params.slug がURLになります。

first-post.md なら /posts/first-post/ になります。

renderで本文を出す

Content Collectionsの記事本文は render(post) でコンポーネントとして取り出します。

const { Content } = await render(post);

その後、Astroコンポーネント内で <Content /> として表示します。

slug生成は共通化する

一覧ページと詳細ページでURL生成ルールがずれると困ります。

ヘルパーを作っておくと扱いやすいです。

import type { CollectionEntry } from 'astro:content';

export function getPostSlug(post: CollectionEntry<'posts'>) {
  return post.id.replace(/\.mdx?$/, '');
}

export function getPostUrl(post: CollectionEntry<'posts'>) {
  return `/posts/${getPostSlug(post)}/`;
}

まとめ

AstroでMarkdown記事詳細を作るなら、流れはこの形です。

  • src/pages/posts/[...slug].astro を作る
  • getCollection() で記事を取得する
  • getStaticPaths() でURLを返す
  • render(post) で本文を描画する
  • slug生成は共通化する

記事URLは後から変えると面倒なので、最初にルールを固定しておくのが重要です。

関連記事

参考