はじめに
このブログはAstro 5で構築しており、記事にはタグを付けて分類しています。
タグ別の記事一覧ページはsrc/pages/tags/[tag].astroという動的ルーティングで実装していましたが、
「CI/CD」のようにスラッシュを含むタグを追加したところ、ビルドが失敗しました。
この記事では、問題の原因と、キャッチオールルートを使った解決方法を記録します。
発生した問題
ChocolateyパッケージのCI/CD移行記事を追加した際、タグに「CI/CD」を指定しました。
---
title: "ChocolateyパッケージのCI/CDをAppVeyorからGitHub Actionsに移行した記録"
tags: ["GitHub Actions", "Chocolatey", "PowerShell", "CI/CD", "Program"]
---
この状態でpnpm buildを実行すると、次のエラーが発生しました。
/tags/CI/CD/index.html Missing parameter: tag
Stack trace:
at getParameter (file:///...astro/dist/core/routing/manifest/generator.js:17:13)
原因
原因は、Astroの動的ルーティング[tag].astroがスラッシュを含むパラメーターに対応していないことです。
getStaticPaths()でタグ「CI/CD」を返すと、Astroは/tags/CI/CD/index.htmlを生成しようとします。
しかし、[tag]は単一のパスセグメントにしかマッチしないため、CI/CDのスラッシュがパス区切りとして解釈されてしまいます。
結果として、/tags/CI/のCD/部分がtagパラメーターとして認識できず、Missing parameter: tagエラーになります。
# Astroの解釈
/tags/[tag] → /tags/CI/CD → NG([tag] = "CI" で "CD" が余る)
# 期待する動作
/tags/[...tag] → /tags/CI/CD → OK([...tag] = "CI/CD")
解決方法
[tag].astroをキャッチオールルート[...tag].astroにリネームしました。
キャッチオールルート(rest parameters)は、 スラッシュを含むパスセグメント全体を1つのパラメーターとしてキャプチャします。
変更内容
変更はファイル名のリネームのみです。
ロジックの変更は不要でした。
# Before
src/pages/tags/[tag].astro
# After
src/pages/tags/[...tag].astro
getStaticPaths()の実装はそのままです。
export async function getStaticPaths() {
const allPosts = await getCollection("posts");
const allTags = new Set<string>();
allPosts
.filter((post) => !post.data.draft && post.data.tags)
.forEach((post) => {
post.data.tags?.forEach((tag: string) => allTags.add(tag));
});
return Array.from(allTags).map((tag) => ({
params: { tag },
props: { tag },
}));
}
タグ「CI/CD」の場合、params: { tag: "CI/CD" }がそのまま/tags/CI/CD/index.htmlを生成します。
タグリンク
テンプレート内のタグリンクも変更不要です。
<!-- タグ一覧ページ -->
<a href={`/tags/${tag}`}>
<!-- 記事詳細ページ -->
<a href={`/tags/${tag}`} class="badge bg-primary">
tagが「CI/CD」の場合、/tags/CI/CDというリンクが生成され、キャッチオールルートに正しくマッチします。
動的ルーティングの使い分け
Astroの動的ルーティングには2種類あります。
| ルーティング | ファイル名 | マッチ対象 | 用途 |
|---|---|---|---|
| 動的ルート | [param].astro | 単一パスセグメント | スラッシュを含まないパラメーター |
| キャッチオールルート | [...param].astro | 複数パスセグメント | スラッシュを含む可能性のあるパラメーター |
今回のケースでは、タグ名にスラッシュが含まれる可能性があるため、キャッチオールルートが適切です。
なお、キャッチオールルートは単一セグメントのパラメーターにもマッチするため、 既存のスラッシュを含まないタグ(「Program」「Astro」など)もそのまま動作します。
影響範囲の確認
今回の変更で影響を受けるのは、タグ別記事一覧ページのルーティングのみです。
次の箇所は変更不要でした。
src/pages/tags/index.astro(タグ一覧): リンク生成のみなので影響なしsrc/pages/posts/[...slug].astro(記事詳細): タグへのリンクは/tags/${tag}で変更不要src/pages/posts/index.astro(記事一覧): 同上src/pages/index.astro(トップページ): 同上
おわりに
Astroの動的ルーティングで、スラッシュを含むタグ名に対応しました。
変更はファイル名を[tag].astroから[...tag].astroにリネームするだけで、
ロジックやテンプレートの修正は不要でした。
タグ名や、スラッシュを含む可能性のあるパラメーターを扱う場合は、 最初からキャッチオールルートを使っておくと、このような問題を未然に防げます。