ブログを Astro に移行した
表題の通り、ブログを Astro に移行した。
Astro はできる限り静的に HTML を生成してくれるツールで、Astro で作った Web サイトは非常に高速な表示ができる。
2023 年現在、注目されているツールでもある。
私は静的サイトジェネレーターが好きで、気になるフレームワークが出るたびにブログを作り直す悪癖があるので、Astro で書き直すことにした。
このブログの技術スタック
- Astro
- Markdoc
- Tailwind
- DocSearch
元々このブログは Next.js と Markdoc で作っていて、使い勝手の良い Markdoc を引き続き使いたいと考えていた。
Astro で Markdoc を使うには、astro-markdoc-renderer を利用することで実現できる。
このライブラリを使って Markdoc に対応させる方法については、以前記事に書いた。
現在、astro のインテグレーションとして @astrojs/markdoc
が実験的に提供されている。
@astrojs/markdoc
使い勝手など、近いうちに試してみたい。
移行してよかったこと
表示が早くなった
そんな気がする。
クライアントサイドでの REST API の実行が ビルド時のみで良くなった
このブログでは、以下のようなカード型の埋め込みリンクができるタグを Markdoc で実装している。
埋め込みリンクの情報にはリンク先の OGP 情報を使っているが、OGP 情報の取得は毎回クライアントサイドで行なっていた。
これは当時、サーバーサイド側 で REST API を実行しようとすると、Markdoc の独自タグで呼ばれるコールバック関数が、非同期処理の完了を待ってくれないためだった。
Astro にしてからはビルド時に OGP 情報を取得できるようになったため、OGP 情報を取得するための API の実行回数が抑えられるようになった。
大変だったところ
コンポーネントの書き換え
動的に生成したい箇所はほぼないため、TSX 形式で書いていたコンポーネントをすべて Astro に書き直した。
これは単純に数が多かったため大変だった。
カスタマイズは程々にしたい。
@docsearch/react を使うとビルドエラーが発生する
このブログでは、サイト内検索に Algolia を利用している。
これまでは Next.js を使っていたため、@docsearch/react というライブラリを使って検索機能を実装していた。
検索ボックスや検索機能の実現にはクライアント側でのレンダリングが必要で、コンポーネントに client:*
を指定する必要があった。
<Search client:load />
このとき、astro dev
では問題なかったが、astro build
を実行すると以下のエラーが出た。
$ npx astro build
// 省略
import { DocSearch } from "@docsearch/react";
^^^^^^^^^
SyntaxError: Named export 'DocSearch' not found. The requested module '@docsearch/react' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS と ES Module の狭間に落ちてしまったようだ。
調べてみると同様のエラーに悩まされている Issue があり、解決方法が示されていたため参考にした。
🐛 BUG: Pseudo ES6 third-party module imports fail when building #3174
まさに Astro のドキュメントでも @docsearch/react を利用したため、同じエラーに遭遇したらしい。
Astro の実装を真似して次のように書くと、astro dev
でも astro build
でも @docsearch/react が提供する機能を利用できた。
import * as docsearch from "@docsearch/react";
const { DocSearch } =
(docsearch as unknown as { default: typeof docsearch }).default || docsearch;
import "@docsearch/css";
export function Search() {
return (
<DocSearch
appId={import.meta.env.PUBIC_ALGOLIA_APP_ID}
indexName={import.meta.env.PUBLIC_ALGOLIA_INDEX_NAME}
apiKey={import.meta.env.PUBLIC_ALGOLIA_SEARCH_API_KEY}
placeholder="Search"
placeholder="Search"
/>
);
}
まだ対応していないところ
- 記事タイトルに合わせて OGP 画像を自動生成する
以前はページ生成の高速化のため、事前にコンテンツの情報をファイルに書き出し、その情報を使って OGP 画像を生成していた。
Astro に移行したとき、ファイルに書き出す処理がなくなったため、それなりの書き直しが必要になっている。
個別ページのルーティングを行なっているgetStaticPaths()
で、画像を生成すれば良さそう。 - 記事一覧のページネーション