SvelteKitでブログを作り直した

Astro + React Components をやめて SvelteKit + Svelte でブログを作り直しました。これでブログを投稿するための障壁が大きく下がりました。これを切っ掛けに、お気軽にブログを投稿していけたらと考えています。

Astroで不満だったところ

Astroはアイランドアーキテクチャを採用したMPAフレームワークです。必要な部分だけをインタラクティブにし、それ以外は静的なHTMLとして配信するゼロJSアプローチによって、非常に高いパフォーマンスを実現します。 当初はこの割り切りが合理的だと感じていたのですが、思いつき駆動で機能を追加していくにつれて、開発体験へのストレスが溜まっていきました。これは別にAstroが悪いわけではなく、Astroの思想から外れた実装が後になって欲しくなってきたことが問題です。 Astroの性質上、各インタラクティブ要素は独立したコンポーネントツリーを持つため、アイランド間でデータを共有する設計も複雑になりがちです。 思いつきで機能を追加していく私にとって、ステートレスな世界を前提とするAstroの思想とのギャップが、次第に無視できないコストになっていました。

と、そんなことを思って SvelteKit + Svelte でブログ兼ポートフォリオ兼CMS的なサムシングを実装していたら、Cloudflare が Astro Technology Company と合流するわ Vite 搭載の新しいローカル開発サーバーが便利そうだわで、面白そうなことをしています。またAstroを使うときが来るかもしれません。

とにかく高速に動くように目指す

Svelte は React や Vue のような仮想 DOMを使用せず、ビルド時にコンポーネントを「DOMを直接操作する効率的な命令型コード」にコンパイルします。これにより、ブラウザでの実行時オーバーヘッドが極めて小さくなり、初期ロードの高速化やスムーズな動作が期待できるらしい。体感でどの程度変わるのだろうと興味を持ったので採用しました。せっかくなので、とにかく高速に動くことを目指しました。

面白かった&良かったのはプリフェッチの実装とSPAトランジションが非常にお手軽なところ。 Astro も View Transitionsprefetch に対応し似たことができるようになりましたが、SvelteKit は SPA 的なナビゲーションを標準で提供しており、ページを跨いだ状態の維持などがより自然に行えます(主観)。

お手軽にウィンドウサイズごとに最適な画像を配信する

フレームワーク変更以外にも色々な実装を追加しました。これまでは最適な画像サイズやフォーマットに変換することは手動で行っていました。とても面倒なのでブログをやめたくなる大きな原因になっていました。今回はCloudflare Images の画像ホスティングとTransformsを利用することで解決しました。

https://ho.lc/i/6sxNlqTCaGYoeSHyqih_Cg/720303e9-d718-438e-c5e1-3f4804d3b600/w1280
https://ho.lc/i/6sxNlqTCaGYoeSHyqih_Cg/720303e9-d718-438e-c5e1-3f4804d3b600/w800
https://ho.lc/i/6sxNlqTCaGYoeSHyqih_Cg/720303e9-d718-438e-c5e1-3f4804d3b600/w640
https://ho.lc/i/6sxNlqTCaGYoeSHyqih_Cg/720303e9-d718-438e-c5e1-3f4804d3b600/w320

事前にブログコンテンツの横幅にあわせた Named Variants を定義しておき、imgタグのsrcset属性にこれら複数のサイズの画像を定義することで、表示サイズに適した画像がブラウザで選択されて最適な画像が配信されます。

記事の作成時は画像のドラッグ&ドロップで Cloudflare Images にアップロードして URL を貼り付けるようにして、Markdown で画像を含む記事を書きやすくしました。mdsvex とカスタムプラグイン (rehypeSmartImage) を組み合わせることで、Markdown 内に書かれた画像リンクは自動的に srcset を持つ最適化された SmartImage コンポーネントに変換するように実装しています。

レイアウトシフトを防ぎつつ画像を表示する

Lighthouse で評価されるレイアウトシフト (CLS) を防ぐための工夫として、20px 幅の軽量サムネイルを Base64 文字列として埋め込みました (LQIP)。これにより、画像の読み込み前にぼやけたプレースホルダーが表示され、CLS を防いでいます。

余計なコンポーネントの排除

以前は写真アルバムをブログポストに投稿するようなことを可能にしていました。これは大変に面倒な作業をする必要がありました。これ、Google Photos のアルバム共有機能でいいんじゃね?ということに気づいたのでコンポーネントを丸ごと削除してアルバム共有のリンクを貼ることにしました。Google Photos のアルバム共有機能、とても閲覧しやすくなっていて最高です。

おわりに

ブログの更新頻度の低さの原因をシステムに押し付けました。 今回これを軽減したので、これまで以上にブログをシュッと書いていける気がします。 Cloudflare Images の画像ホスティングのために 5 USD ほど毎月課金することになるので、お金が引き落とされるたびにブログのことを思い出していきたいと思います。