コピペ地獄からの解放!Astroの動的ルーティング入門♪

#技術#Astro#チュートリアル#Web制作#初心者向け
ねつきのトーク
ねつき
ねつき
コピペ地獄からの解放!Astroの動的ルーティング入門♪
ねつき
ねつき

お兄ちゃん〜、昨日のAstro入門の続きだよ♪

今日は動的ルーティングについて説明するね(´∀`)

お兄ちゃん
お兄ちゃん

動的ルーティング?

ねつき
ねつき

うん!例えばブログ記事が100個あるとするでしょ?

普通に考えたら100個のHTMLファイルが必要だよね。

お兄ちゃん
お兄ちゃん

まあ、そうだね。

ねつき
ねつき

でもAstroなら、1つのテンプレートファイルで100ページ全部生成できるの!(≧∇≦)

コンテンツは別で用意するけど、テンプレートのコピペ地獄からは解放されるよ♪


静的ルーティングのおさらい

ねつき
ねつき

まず普通のルーティングをおさらいするね。

Astroではsrc/pages/の中のファイル構造がそのままURLになるの♪

src/pages/
├── index.astro      → /
├── about.astro      → /about
└── blog/
    └── index.astro  → /blog
ねつき
ねつき

これが静的ルーティング。ファイル1つ = ページ1つ、シンプルでしょ?(´∀`)

お兄ちゃん
お兄ちゃん

わかりやすいね。


動的ルーティングの基本

ねつき
ねつき

じゃあ本題!

ブログ記事のURLって、こんな感じになることが多いよね。

/blog/first-post
/blog/second-post
/blog/third-post
...
ねつき
ねつき

これを静的ルーティングでやろうとすると…

src/pages/blog/
├── first-post.astro
├── second-post.astro
├── third-post.astro
...(100個続く)
ねつき
ねつき

100記事あったら100ファイル!(´;ω;`)

しかも中身はほとんど同じテンプレートなのに…

お兄ちゃん
お兄ちゃん

それは確かに大変だ。

ねつき
ねつき

そこで動的ルーティングの出番!

ファイル名に[角括弧]を使うの♪

src/pages/blog/
└── [slug].astro    → /blog/first-post, /blog/second-post, etc.
ねつき
ねつき

[slug].astroっていう1つのテンプレートで、すべての記事ページを生成できるんだよ(´∀`)


getStaticPathsで経路を定義

ねつき
ねつき

動的ルーティングを使うには、getStaticPathsっていう関数をエクスポートするの。

「このページは何パターン生成するか」を教えてあげる関数だよ♪

---
// src/pages/blog/[slug].astro

export function getStaticPaths() {
  return [
    { params: { slug: 'first-post' } },
    { params: { slug: 'second-post' } },
    { params: { slug: 'third-post' } },
  ];
}

const { slug } = Astro.params;
---

<h1>記事: {slug}</h1>
お兄ちゃん
お兄ちゃん

なるほど、配列で「生成したいパターン」を返すのか。

ねつき
ねつき

そう!これをビルドすると、こうなるの♪

dist/
└── blog/
    ├── first-post/index.html
    ├── second-post/index.html
    └── third-post/index.html
ねつき
ねつき

1つのAstroファイルから、3つのHTMLが生成されたの(≧∇≦)


propsでデータを渡す

ねつき
ねつき

でも実際のブログって、タイトルとか本文とかあるでしょ?

paramsだけじゃなくてpropsも渡せるの♪

---
// src/pages/blog/[slug].astro

export function getStaticPaths() {
  const posts = [
    { slug: 'first-post', title: '最初の記事', content: 'こんにちは!' },
    { slug: 'second-post', title: '2番目の記事', content: 'またね!' },
  ];

  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { title: post.title, content: post.content },
  }));
}

const { slug } = Astro.params;
const { title, content } = Astro.props;
---

<article>
  <h1>{title}</h1>
  <p>{content}</p>
</article>
お兄ちゃん
お兄ちゃん

paramsがURLのパラメータで、propsがページに渡すデータか。

ねつき
ねつき

そうそう!

実際にはMarkdownファイルから読み込んだり、APIから取得したりすることが多いよ♪


複数階層もOK!レストパラメータ

ねつき
ねつき

もっと深い階層のURLも作れるの!

[...slug]っていう書き方を使うよ♪

---
// src/pages/docs/[...slug].astro

export function getStaticPaths() {
  return [
    { params: { slug: undefined } }, // → /docs
    { params: { slug: 'getting-started' } }, // → /docs/getting-started
    { params: { slug: 'guides/routing' } }, // → /docs/guides/routing
    { params: { slug: 'guides/styling' } }, // → /docs/guides/styling
  ];
}

const { slug } = Astro.params;
---

<h1>ドキュメント: {slug || 'トップ'}</h1>
お兄ちゃん
お兄ちゃん

...を付けると階層を跨げるのか。

ねつき
ねつき

うん!GitHubみたいな複雑なURLも表現できるの(´∀`)

/[org]/[repo]/tree/[branch]/[...file]

/withastro/astro/tree/main/docs/public/favicon.svg
ねつき
ねつき

こんな複雑なパスも1つのテンプレートで!(゚∀゚)


実際の使用例:このサイトの多言語対応

ねつき
ねつき

このサイトでも動的ルーティング使ってるんだよ♪

多言語対応(i18n)のために[...lang]を使ってるの。

src/pages/
└── [...lang]/
    ├── index.astro      → /, /en
    ├── profile.astro    → /profile, /en/profile
    ├── diary/
    │   └── [...slug].astro  → /diary/2025-12-09, /en/diary/2025-12-09
    ...
ねつき
ねつき

日本語版と英語版、同じテンプレートから生成してるの(≧∇≦)

---
// src/pages/[...lang]/index.astro

export function getStaticPaths() {
  return [
    { params: { lang: undefined }, props: { lang: 'ja' } }, // → /
    { params: { lang: 'en' }, props: { lang: 'en' } }, // → /en
  ];
}

const { lang } = Astro.props;
---

<h1>{lang === 'ja' ? 'ようこそ!' : 'Welcome!'}</h1>
お兄ちゃん
お兄ちゃん

なるほど、undefinedで日本語版、'en'で英語版になるのか。

ねつき
ねつき

そうなの♪

デフォルト言語(日本語)はURLに言語コードが付かないようにしてるんだ(´∀`)


ねつき的まとめ

ねつき
ねつき

動的ルーティングのポイントをまとめるね♪

お兄ちゃん
お兄ちゃん

1つのテンプレートで複数ページ生成できるのは便利だね。

ねつき
ねつき

でしょ?(≧∇≦)

  • ブログ記事100個 → テンプレートは[slug].astroの1つだけ

  • 商品ページ1000個 → テンプレートは[id].astroの1つだけ

  • 多言語対応 → [...lang]フォルダでテンプレート共通化

コンテンツは別で用意するけど、テンプレートのコピペからは解放されるの♪

お兄ちゃん
お兄ちゃん

Astroよくできてるな。

ねつき
ねつき

次回はContent Collectionsについて話そうかな?

Markdownファイルを型安全に扱う方法だよ♪

お楽しみに〜(´∀`)

♪ 拍手 ♪
0 拍手