Back to posts

GatsbyからAstroへ移行した理由:判断軸の整理

このサイトは2019年にGatsbyで作りました。当時はGatsby 2系が現役で、Reactでブログが書けること自体が新鮮だった頃です。ところが記事の投稿は2020年で止まり、リポジトリの最終コミットも2020年12月。それから数年、手を入れないまま時間が経ちました。

再開するにあたって最初にぶつかったのが、「このGatsbyを今の環境で動かせるのか」という問題です。Gatsby 2系とnode-sass 4という当時の組み合わせは、今のNode.js環境ではビルドが通るかどうか自体が怪しい。仮に通ったとしても、その先で依存パッケージを1つずつ延命していく作業が待っています。ブログを再開したいのに、再開前の整備で力尽きるのは本末転倒でした。

そこでフレームワークごと載せ替えることにして、移行先にAstro 5を選びました。この記事では、その判断の軸を整理しておきます。同じように「数年放置したGatsbyブログをどうするか」で悩んでいる人の参考になればと思います。

「Gatsbyのまま直す」を選ばなかった理由

先に、残す選択肢を検討しなかったわけではない、という話から。

Gatsby自体は今も公開されていて、5系が現行のメジャーバージョンです。ただ、2023年にNetlifyがGatsbyを買収して以降は、大きな新機能の追加よりも保守が中心になった、という見方が一般的になっています。プラグイン側も更新が続いているものと止まっているものの差が開いてきている印象です(このあたりは個別のパッケージごとに状況が違うので、自分のサイトで使っているプラグインの最終更新日を1つずつ確認するのが確実です)。

自分のサイトの場合、問題はGatsby 5へのアップグレードパス以前のところにありました。2系から5系へは実質的に作り直しに近い作業量になるうえ、上げた先でもプラグイン依存の保守からは逃げられません。「直す」と「作り直す」のコストが近いなら、作り直すときに今の自分に合った道具を選ぶ方がいい、というのが最初の判断でした。

判断軸は3つだけに絞った

まず、2つの選択肢の違いを表で並べておきます。

観点GatsbyのままAstroへ移行
配信JSページ全体をReactのランタイムとJavaScriptで組み立てるデフォルトでクライアントサイドのJavaScriptは出荷せず、静的HTMLを生成。動的な部品だけをアイランドとして読み込む
データ取得GraphQL経由が前提で、画像・サイトマップ・フィードも専用プラグインで設定するgetCollection() のような通常の関数呼び出しに寄っていて、GraphQLの層がない
保守依存が多く、どれか1つがNodeやReactのバージョンアップに追従できなくなるとサイト全体のビルドが止まるプラグインの数自体が公式インテグレーションで足りる範囲に収まりやすく、「壊れる場所を減らす」ことができる
記事資産の扱いMarkdownファイル(取得はGraphQL経由)Markdownファイルそのものを持ち運べる。frontmatterをContent Collectionsのスキーマに合わせて整えれば、記事本文に手を入れる必要はほとんどない

1. 静的ブログにSPAのJSは要らない

このサイトでやっていることは、記事を表示すること、記事の一覧を出すこと、プロフィールページを見せること。それだけです。画面遷移のたびにReactのランタイムを読み込んで、ページ全体をJavaScriptで組み立てる必然性は、冷静に考えるとありませんでした。

AstroはデフォルトでクライアントサイドのJavaScriptを出荷せず、ページを静的HTMLとして生成します。カルーセルのような動的な部品が必要になったら、その部品だけを「アイランド」として切り分けてJavaScriptを読み込ませる設計です。ブログで動的な部品と言うと、せいぜい検索窓や目次くらい。大部分がHTMLで完結するサイトなら、出発点が「JSゼロ」の方が素直です。

2. 依存とビルドの保守を軽くしたい

Gatsby時代の構成を思い返すと、記事を出すだけのサイトのわりに依存が多かったです。データ取得はGraphQL経由が前提で、画像の最適化も、サイトマップも、フィードの生成も、それぞれ専用プラグインを入れて設定する形でした。便利だった反面、どれか1つがNodeやReactのバージョンアップに追従できなくなると、サイト全体のビルドが止まります。放置していた数年で、その弱さを身をもって知りました。

Astroでは記事データの取得は getCollection() のような通常の関数呼び出しに寄っていて、GraphQLの層がありません。プラグインの数自体も、公式インテグレーションで足りる範囲に収まりやすい。劇的に何かが変わるというより、「壊れる場所を減らす」ための移行だと思っています。

3. Markdownの記事資産は、そのまま運べる

移行をためらう一番の理由は、過去記事の扱いでした。この点はAstro公式の移行ガイドでも触れられているとおりで、Markdownファイルそのものは基本的に持ち運べます。frontmatterの項目をContent Collectionsのスキーマに合わせて整えれば、記事本文に手を入れる必要はほとんどありません。

const posts = await getCollection("blog");

記事の一覧もこうした取得の延長で書けます。長く続ける前提のブログでは、「本文はただのMarkdownファイルとして残る」という性質が効いてきます。フレームワークをまた替える日が来ても、資産はファイルのまま残るからです。

移行で実際に手が止まる場所

判断は簡単でも、作業で詰まる場所はだいたい決まっています。自分の場合は次の3か所でした。

画像まわり。 Gatsbyでは gatsby-plugin-image のコンポーネントで書いていた画像を、Astroでは astro:assets の <Image /> に置き換える必要があります。記法が違うだけでなく、画像ファイルをどこに置くか(src 配下に置くと最適化の対象になる)も変わるので、記事数が多いサイトほど機械的な置換と目視確認の両方が要ります。

プラグイン前提のコード。 GraphQLのクエリ、gatsby-node.js でのページ生成、<Link> コンポーネント、<Helmet> でのメタ情報管理。どれもAstroには対応物があって、ページ生成は動的ルートと getStaticPaths()、メタ情報はレイアウトの <head> に直接書く形になります。ただ「対応物がある」と「そのまま動く」は別で、結局テンプレート側はほぼ書き直しになりました。ここは最初から書き直し前提で見積もった方が安全です。

URLの維持。 一番神経を使ったのがここです。過去記事のURLが変わると、外部からのリンクも、検索エンジンの評価も切れてしまいます。移行前に旧サイトのURL一覧を洗い出して、slugをそのまま引き継ぐか、引き継げないものはリダイレクトを設定する。地味ですが、移行作業の中で先送りできない部分です。

移行を判断するときのチェックリスト

最後に、同じ判断をする人向けに、自分が使った観点を並べておきます。

  • 旧サイトは今のNode.js環境でビルドが通るか。通らない場合、延命と作り直しのどちらが安いか
  • サイトに必要な動的機能は何か。記事表示と一覧だけで完結するなら、SPA型のフレームワークである必要は薄い
  • 依存しているプラグインの最終更新日。止まっているものが多いほど、残す選択肢のコストは上がる
  • 記事本文はMarkdownファイルとして取り出せるか。取り出せるなら、移行のハードルは大きく下がる
  • 旧URLの一覧を用意できるか。維持できないURLにはリダイレクトの計画があるか

逆に、Gatsby 5系で現役稼働していてビルドも安定しているサイトなら、慌てて移る理由はないと思います。今回の判断は「2系で数年放置」という自分の条件ありきのものです。

構成としては、Astro 5にTailwind CSS 4とTypeScript、記事はContent Collectionsで管理し、検索はPagefind、テストはPlaywrightで回す形にしました。派手な構成ではありませんが、数年後にまた触るとき、自分が困らない形にはなったと思っています。なお、公開先をNetlifyからCloudflare Pagesへ移す作業の方は、NetlifyからCloudflare Pagesへ移すときのチェックリストに分けました。

参考