ブログを Astro に移行しました

大変大変お久しぶりです、白澤です。先月 23 歳になりました。Novalumo も 5 歳になりました。
どうやらブログを更新するのが年に 1 回になってしまいそうです。と書こうとしたら Copilot に心を読まれていました、、、
もちろん仕事してないわけないですね、結構いろんなプロジェクトが並列で走っているのでバタバタです。もっと AI 使える場面が増えて欲しいなー。
なんなら今は決算時期で会計に手をつけてなかったので夏休みの宿題みたいになってます。学生時代に宿題しなかった癖が抜けてないですね。あ、クライアントワークは基本ちゃんとやってますよ。自社作業は後回しにしがちです。
さて、タイトルの通りですが、ブログを Astro ↗ に移行してみました。
経緯
コーポレートサイトはこの記事を書いている現在 Next.js ↗ で作っていて、その中にブログページを追加していました。記事の管理はニュースと同様に microCMS を使っていて、ブログ記事データの立ち位置としては、あくまでニュースのカテゴリー「ブログ」のような感じで運用していました。
これが結構しんどくて、まずそもそも設計ミス感がすごかったです。ブログ記事にもカテゴリーあるやろがい、なんで「ブログ」がカテゴリーになってんねんというのに気づいたとか。あと、方針として記事データ系をマークダウンで管理したいとか。色々ありました。
それで、思い切ってまずはブログをコーポレートサイトのリポジトリから切り離そうかと。
Next.js から Astro へ
まず最初にやったのが Next.js のブログ用のプロジェクトを立てることでした。が、結論から言うとマークダウン管理の SG なブログを実装するのに個人的には Next.js はあまり向いていないと感じました、んでやめました。ここから Astro へ移行することになります。(Astro は案件で数回だけ触ったことがありましたが、マークダウン系は全くノータッチ。)
ただ、その時点では結構フロントエンドを React で実装していたので(というより AI に結構実装してもらっていたので API 使用料とか勿体無くて)、コンポーネントやページ系を勢いで AI (OpenHands ↗ @ Claude ↗ 3.7 Sonnet) に頼んで Astro の形式に移行してもらうことにしました。
使ったのは最近話題の Devin ↗ です。Devin 2.0 が登場したことで料金プランも良心的になって使いやすくなりましたよね。
ファイル変更数 25, +1,490 -488
のプルリクを作成してマージされるまでに使った ACU はざっくり 3 くらいでした。
あ、Devin くん使ってみたいよって方は是非こちら ↗からどうぞ!ここからの登録で Team プランの場合は 100 ACUs, Core プランの場合は 10 ACUs もらえます!アナタモワタシモ。
これである程度は Astro で動くようになったので、あとは自分で手作業で微調整していきます。
Devin からバトンタッチ
修正しなければいけなかった部分は Astro のバージョンまわりでした。Devin に任せた結果インストールされた Astro のバージョンは 4 系でした。現在は 5 系が最新なので、まずはアップデート作業をします。さ、アップデートしよ?
大体のフレームワークはアップグレードガイドを提供してくれているのでそれに従って上げていきます。
https://docs.astro.build/en/upgrade-astro/ ↗
npx @astrojs/upgrade
# Bun を使っているのでこっちで
bunx @astrojs/upgrade
ここでトラップ。こんな記事を見つけました。
Astro 5.x への移行はなかなかハマりどころが多い | zenn.dev ↗
Content Collection の仕様が結構変わったみたいです。まあこの辺は触ったことなかったので移行作業というより初見作業。
Devin の生成コードは 4 系の内容だったので、5 系に直す作業をドキュメント読みつつ進めました。
Astro はいいぞ
Content Collection まわりをこの際初めて触ってみましたが、結構良いですね。マークダウン管理のブログを作るのは多分一番難易度低い気がします。
content.config.ts
にこんな感じで:
import { defineCollection, z } from "astro:content";
import { glob } from "astro/loaders";
const articles = defineCollection({
loader: glob({ pattern: "**/*.md", base: "./content/articles" }),
schema: z.object({
draft: z.boolean().optional(),
title: z.string(),
excerpt: z.string(),
publishedAt: z.string().transform((dateString) => new Date(dateString)),
updatedAt: z
.string()
.optional()
.transform((dateString) =>
dateString ? new Date(dateString) : undefined
),
author: z.string(),
category: z.enum(["article", "tech"]),
tags: z.array(z.string()),
coverImage: z.string().optional(),
}),
});
export const collections = { articles };
Collection を定義できて、これをいろんなところで使えます。
getCollection
とか getEntry
みたいなのが使えて、これがシンプルながらめっちゃ便利でした。
// 記事一覧を取得
const posts = await getCollection("articles", ({ data }) => !data.draft);
// 記事1つを取得
const post = await getEntry("articles", id);
content.config.ts
で collections
を export
してあるけどどう使うんだろう?と思ったら、なんと getCollection
とかの引数に渡す文字列に型がついてました。
// 戻り値にはこの形でデータが返ってくる
type Post = {
id: string;
body?: string;
collection: "articles";
data: InferEntrySchema<"articles">;
rendered?: RenderedContent;
filePath?: string;
};
export
した名前の文字列を引数として渡すと、なんとその戻り値にも schema
で定義した型でデータが返ってきます。これは開発体験が非常に良かった!
なんかこれだけでも小規模なサイトで Next.js で作ってたものは Astro に移行しようかなと思えました。本当に書いてて心地が良い。圧倒的に楽。
まとめ - Astro は Next.js に疲れた人へのオアシス
最近は App Router しかり、RSC (React Server Component) しかり、React 界隈並びに Next.js 界隈は色々と新しい技術が出てきていて、結構複雑になってきている気がしています。
結構前は Novalumo のコーポレートサイトは Vue.js の Nuxt.js で作っていて、そこから今でこそ Pages Router と呼ばれるようになった Next.js に移行しました。ちょっと前にこの Pages Router で実装されたものも頑張って App Router に移行しましたが、控えめに言ってかなり大変でした。
App Router に対応することで色々と動的に生成する部分だったり色々便利になったりしましたが、やはり複雑さは拭えません。実際結構保守が大変になってきました。(これはこれで良い教材になっていると思いますが)
ですが、Astro はこの辺かなりシンプルで、あまり複雑に考える必要がありません。しかも、使おうと思えば Astro と一緒に Vue や React などを使うこともできるので、結構自由度が高いです。また、これは Astro の売りですが、Astro が生成するのは基本的に HTML で、必要な部分だけ JS を読み込むという形なので、パフォーマンスも良いです。これが結構大きいですね。
便利ながら複雑ではない Astro, Next.js に疲れた方は試してみても良いかもしれません。
ディスクレーマー的な何か
決して Next.js を否定しているわけではありません、実際 Next.js の便利さを享受しているうちの 1 人です。Next.js は、よりアプリ性を求められるものには非常に向いていると思います。
あとがき?
久々に結構な文章量書いた気がします。Copilot の補完が出てきたりして、書きたい内容ならそのまま Accept してどんどん書き進めていけたのでスムーズでした。ブログ記事とかは自分の言葉で書きたいので、最近の AI 生成記事はあまり好きではないですが、お手伝い程度(それこそ副操縦士)として使うのは良いですね。
ただ、コンテンツとして記事を量産したいという気持ちも少し理解できるので、自分がやるとしたら過去の自分の記事を AI に学習してもらって、自分と似たような書き方で記事を書いて欲しいし、最終的に自分が確認して公開するという形が良いかなと思いました。あくまで自分の言葉で書きたいので。
せっかく Astro に移行して快適な環境になったので、また可能な限り更新していきたいなと思います。
書いていて、「この記事って読むのに何分かかるんだろう?」と思ったので、「この記事は n 分で読めます」みたいな機能も実装してみたいですね。