背景
Astro 6 へのバージョンアップに向けた下ごしらえの2つ目です。1つ目では、Cloudflare の環境変数などを取り出す書き方を、共通関数1つに集めました。
今回は、開発ブログと wiki の Markdown 記事の読み込み方です。
何が変わるのか
Astro では、Markdown で書いた記事の集まりを「コンテンツコレクション」と呼びます。Astro 5 には古い形式と新しい形式の2つがあり、このサイトは古い形式を使っていました。Astro 6 では古い形式が廃止され、古い設定ファイルがあるだけでエラーになります。
| 項目 | 古い形式 | 新しい形式 |
|---|---|---|
| 設定ファイル | src/content/config.ts |
src/content.config.ts |
| 記事の読み込み方 | type: 'content'(フォルダを自動で読む) |
loader: glob(...)(読むフォルダを指定する) |
| 記事の名前(URLになる部分) | entry.slug |
entry.id |
| 本文を表示用に変える | entry.render() |
render(entry) |
Astro 5 は新しい形式にすでに対応しているため、バージョンアップの前に、今のバージョンのまま移せます。
対処
1. 設定ファイルを新形式で作り直した
開発ブログ(src/content/devblog/)と wiki(src/content/wiki/)を、glob ローダーで読むように設定しました。記事のURLはファイル名から作られます。新しい形式でも同じ規則でURLが作られるため、記事のURLは変わりません。
調べる途中で、古い設定には少し食い違いがあることにも気づきました。項目の決まり(スキーマ)は、中身が空の別のコレクションに付いていて、実際の開発ブログ記事には付いていませんでした。今回は「ふるまいを変えない」ことを優先し、この状態をそのまま新形式に移しています。
2. 呼び出し側の書き換えを最小にする共通関数を挟んだ
entry.slug と entry.render() は、サイト中の多くの場所で使われていました。中には、データベースから読んだ値の slug と同じ名前で並んでいる場所もあり、1つずつ書き換えると取り違える恐れがありました。
そこで、新しい形式で読んだ記事に slug と render() を付け足して返す共通関数を作りました。
// 新しい形式で読んだ記事を、今までと同じ形に整えて返す
export async function getContentEntries(name, filter) {
const entries = await getCollection(name, filter);
return entries.map((entry) => ({
...entry,
slug: entry.id, // 古い形式の slug は、新しい形式の id
render: () => render(entry), // 本文の表示用変換
}));
}
呼び出し側は、getCollection を getContentEntries に置き換えただけです。
確かめたこと
移す前と後で、ビルド成果物(ビルドで出来上がったファイル一式)を本番と同じ実行環境(workerd)で動かし、次のページの出力を保存して見比べました。
| ページ | 結果 |
|---|---|
| 開発ブログの一覧・記事ページ | 完全に同じ |
| wiki の一覧・用語ページ | 完全に同じ |
| 年別アーカイブ・RSS | 完全に同じ |
| サイトマップ | 載っている記事は同じ。並び順だけが変わった |
サイトマップの並び順は、検索エンジンの扱いに影響しません。
学んだこと
- 大きな書き換えでは、前後の出力をそのまま保存して見比べると、「何も変わっていない」ことを確実に示せます
- 名前が同じで中身が違う値(記事の
slugとデータベースのslug)が混ざっている場所は、1つずつ書き換えるより、取り出し口で形を合わせるほうが安全です