概要
1年半ほど Next.js で運用してきたサイトを Astro で書き直した。
実装のポイント
Freeze everything ❄️
検索していて、あるサイトに出会った。フロントエンドの技術を調べていたときだった。サイトの概要文にはいくつかのキーワードが書かれていた——「(あるモダンなフレームワークの名前)」、「静的サイト生成」、云々、云々。とっても素晴らしい。期待してアクセスした。
ページに入ると、はじめにブラウザのデフォルトのフォントでレンダリングがおこなわれた。見たところこのサイトは、余分な装飾も少なく、比較的ミニマルらしい。そう思ったとたん、画面がフラッシュし、スタイリッシュな字体がドカッと降ってきた。Web フォントのお出ましだ。息つく間もなく、確定済みのレイアウトを押しのけて外部の画像が割り込んでくる。同時に、埋め込まれていた <iframe>
が正体を現し、なにやらスクリプトもガチャガチャとロードされた。この間およそ数秒。
いったい何が起こったのか?
答え:たとえ静的生成された(SSG)サイトであっても、すべてのリソースがビルド時に解決されるわけではない。Google Fonts 用のスタイルシートや、外部の画像への参照、<iframe>
による外部コンテンツの呼び出し……こうしたリソースの解決はしばしばクライアント側に委ねられ、(よほどひどい場合)上のような事態をもたらす。逆にいえば、もし SSG をさらにチューニングするのなら、このあたりには改善の余地がある。単純な話だ。とにかく、可能な限りのものをビルド時に凍結して、バンドルに含めてしまえばよい。ここで重要な真理をひとつ——たいていの場合、なにごとも決定論的であるほうが喜ばしい。
1. リンクカード内の画像
以前の実装 以来、Markdown 内の単独のリンクはリンクカード(👇 こういうの)に変換され、リンク先の Open Graph 画像などが表示されるようになっていた。
この画像は外部のものをそのままリンクしていたので、Lighthouse のパフォーマンス診断をかけると、サイズがデカすぎるから減らせと怒鳴られることがあった。そこで、画像をいったん取得し、sharp で適正なサイズに縮小(ついでに WebP に変換)して base64 形式でドキュメントに埋め込んだ。これでクライアント側での余剰なリクエストが減り、総転送量が抑えられる。
代償として、1. ドキュメント自体のサイズが増え、2. ビルド時間がやや長くなる ところだが、さいわいこの記事数・リンク数ではそれほどの影響はなかった。さらにいえば画像の取得結果は軽くキャッシュされる実装になっているので、一度アクセスすれば(少なくとも開発サーバのセッション内では)応答速度も悪くない。
2. OG画像の生成
こちらから提供する OG 画像についても、Edge Function で動的に応答させる方式を改め、ビルド時に生成することとした。静的ファイルのエンドポイントを作成する機能を使い、記事一覧から勝手に画像が生えてくるようにしている。

3. @fontsource-variable
の活用
Web フォントを NPM パッケージからインポートすることで、まとめてバンドルし、セルフホストできる。こういうことができるのは JavaScript のフレームワークを使う強みだ。
せっかくなのでバリアブルフォントを使ってみた。軽量で便利なのではやく普及してほしい。地に平和がありますように。バリアブルフォントが広まりますように。
画像処理のワークフロー 🏭
Astro v3 では、Markdown / MDX 内の画像を最適化するいくつかの方法が公式に提供されている。しかしながら、それらはみな
- 「MDX や Astro コンポーネントの内部で個別に画像をインポートし /
<Image>
コンポーネントに代入して処理をカスタマイズする」 - 「通常の Markdown の記法で画像を挿入し / Astro 側が自動で行う処理に甘んじる」
のいずれかであって、 3. 「Markdown の記法で挿入し / <Image>
コンポーネントでカスタマイズ」したい私の願いとは相容れなかった。そのため、Markdown の処理時に <img>
要素を <Image>
コンポーネントに置き換える方法で対応した。
注意点としては、
- コンポーネントの置き換えを使うには、たとえファイル名だけでも
.mdx
にしなければならない(Plain Markdownでは不可能) - 最終的にバンドルに含められる関係上、
<Image>
内の画像は必ずどこかでインポートしたものでなければならない
など。後者については、個別の画像ごとではなく、import.meta.glob()
を使ってフォルダ内の画像をまるごとインポートすることで対処した。
スタイル面・その他 ✨
スタイルは大きくは変えていないが、ちょっと「洗練」が入った(要検証)。あとリセット CSS (preflight.css
) のみを残し、Tailwind を剥がした。
ホスト先は Vercel + Cloudflare の二重構成をやめ、Cloudflare Pages にがっちり腰を据えた。
総評
全体的に開発体験が良くなった。コンテンツコレクションのおかげで Markdown / MDX に型が付くし、Vite ベースのモダンなエコシステムでやっていけるのは嬉しい。
パフォーマンスについては以前の実装でも十分すぎるほどだったが、今回の改修で全体の転送量がかなり減った。
ところで記事のほうは何か増やされたんですか?