このブログをAstro 2.xから3にアップグレードしました。

2023/08/30にAstro 3.0がリリースされたので、このブログも2.10から3.0へアップグレードしました。

Astro 2.0のリリースが今年の1月だったので、メジャーアップデートがむちゃくちゃ早いと感じました。

Astro 2.xからの変更点

公式ドキュメントがわかりやすいのと、grip on mindsさんの記事が本当に素晴らしいのであまり言及することがないです。

参考までに、このブログで修正が必要だった箇所を挙げていきます。

デフォルトのImage ServiceがSquooshからSharpに変更された

2.xでExperimentalだった画像最適化機能のastro:assetsが3.0で正式版になりました。やったぜ。

2.xではImage ServiceにSharpを使用する場合defineConfigsharpImageService()の指定が必要でしたが、 3.0ではデフォルトにSharpが採用されたため、その指定が不要となりました。

なお、Squooshの開発が停止していたのをこの作業で初めて知りました。
add support for node engine 18 for @squoosh/lib · Issue #1242 · GoogleChromeLabs/squoosh
経済的な問題で停止したというのがあまりにも悲しい。

getStaticPaths()で戻り値の配列がフラット化されなくなった

2.xではgetStaticPaths()の戻り値は自動でフラット化されていましたが、3.0では多次元配列のままリターンされるようになりました。 戻り値が多次元配列になっているとInvalidGetStaticPathsEntryエラーが返ってきます。

InvalidGetStaticPathsEntry: Invalid entry returned by getStaticPaths. Expected an object, got ENTRY_TYPE

このブログでは、/src/pages/[tag]/[page].astroのようにネストされたページネーション部分がエラーになりました。 paginate()が配列を返してくる都合上、ネストされたページネーションをmap()で実装すると多次元配列が生成されてしまいます。

ページネーションのドキュメントではmap()ではなくflatMap()を使用するように変更されていました。

このブログもドキュメントに倣いflatMap()で修正しました。

HTTP request methodsの指定が小文字から大文字になった

カスタムエンドポイント用のHTTP request methodsの指定が小文字から大文字になりました。 このブログはSSGなので関係ないと思っていたのですが、実はRSSの生成にget()を使っていてWarningが出たので修正しました。

なるほどRSSの生成はカスタムエンドポイントを使っていたんですね。 SSRのルーティングに使う機能だとばかり思っていましたが、 SSGだとビルド時に呼び出されて静的コンテンツが出力される仕組みでした。便利ですね。

verbatimModuleSyntaxがデフォルトでtrueになった

そもそもverbatimModuleSyntaxがなんなのか分からなかったので調べるところから始めました。

TypeScript 5.0 introduces a new option called —verbatimModuleSyntax to simplify the situation. The rules are much simpler - any imports or exports without a type modifier are left around. Anything that uses the type modifier is dropped entirely.

このブログの場合、algoliasearch使用時に型なのか値なのか見ただけでは判断し難いimport文を記述していましたが、 そのようなimport文はverbatimModuleSyntaxでエラーになります。

/** Before **/
// 'SearchClient' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. でエラーになる
import algoliasearch, { SearchClient } from "algoliasearch/lite";
/** After **/
// type修飾子を使って書き直す -> わかりやすくなった🎉
import algoliasearch, { type SearchClient } from "algoliasearch/lite";

副作用がなさそう、かつ、有効にしたほうが便利なので、このブログではデフォルト値のtrueを採用しました。

markdown.draftが廃止された

Astro 2.xでは、Front Matterにdraft: trueを指定したページを、prodのビルド対象から除外する(devでは閲覧できる)機能があります。
しかし、実際のところ「ビルドはされないがsitemapにURLが出力される」「コンテンツコレクションではdraftフラグは無視される」といった、一貫性のない動きをしていました。

正直、あまりにも初見殺しがすぎる挙動だと思っていたので、廃止されてよかったです。

アップグレード時に詰まったところ

詰まったところは特になかったのですが、2.xから直っていないバグとおま環っぽい事象で困りました。

トレイリングスラッシュの扱いがdevとprodで異なる箇所がある

2.xの時点でAstro.url.pathnameのスラッシュの扱いがdevとprodで異なっており、 「defineConfigtrailingSlash: neverを設定しているにもかかわらず、prodだとトレイリングスラッシュがつく(devではつかない)」という問題があります。

残念ながら3.0リリース時点では解決していません。

VSCodeでPrettierが効かないしなんならTypeScriptのIntelliSenseも効かない

おそらくおま環だと思います。良い機会だったのでnpmからpnpmに乗り換えた上でastroのインストールからやり直しました。

また、このブログはベースとして拝借しているテーマがあり、元の設定をそのまま使用していたのですが、 package.jsonの内容含め色々思うところがあったため、動作に影響が出ない範囲で気になるところを修正しました。

これらの作業で無事にVSCodeの拡張機能が動作するようになりました。Prettierもアップグレードできたので結果的には作業して良かったです。

Astro 3.0にアップグレードしてみて

3.0はSSR機能強化とパフォーマンス向上に重きをおいていることもあり、このブログに関してはそこまで変わったところはないと感じています。 とはいえ、画像最適化の敷居が低くなっただけでもアップグレードするメリットは十分にありましたし、 作業の過程で知らない機能を知ることができたので、やってよかったと思いました。

所感

エラー文にすべきことが書いてあったのと、公式ドキュメントがわかりやすかったのでほぼ詰まらずに作業を進めることができました。 このブログでは(私の体調面の問題から)メンテナンスコスト削減のために作りを極力シンプルにしていたので、 抵抗感なくアップグレード作業を開始できたのも良い点でした。

なお、Astroが1年に2回もメジャーアップデートをリリースしている間Gridsomeには一切動きがありませんでした。
Upgrade to Vue 3.x · Issue #1289 · gridsome/gridsome
Vue 3対応、Gridsomeじゃなくても相当難しいと思うので開発止まっても仕方ない気持ちがあります。