2ヶ月触った人間が語るAstroの設計原則

#Astro
2ヶ月触った人間が語るAstroの設計原則

Astroとは

  1. コンテンツ駆動: Astroは、コンテンツを上手く表示するために設計されています。
  2. サーバーファースト: HTMLをサーバーでレンダリングすることで、ウェブサイトの動作が速くなります。
  3. デフォルトで高速: Astroで遅いウェブサイトを作成することは不可能であるべきです。
  4. 簡単に使える: 専門家でなくても、Astroで何かを作成できます。
  5. 開発者を重視: 目的を達成するために必要なリソースが揃っているべきです。

上記はAstroの公式サイトで上げられている「5つの核となる設計原則」である。本サイトはAstroを使って作成されているが、色々とみてもらえれば分かってもらえるようにWebアプリではなく、あくまでコンテンツを共有するために作られたWebサイトである。そういった意図とAstroの設計原則が合致してそうだなと思い、技術選定にてAstroを使うことに決めた。 本サイト作成において、デザイン周りでまだ不安や改善点は山ほどあるけれど、Astroの機能は一通り使ってみたため、語るための記事を書いていこうと思い立った。ひとまずAstroが掲げる設計原則について、2ヶ月ほどAstroを触りまくって設計思想と触れ合った所感を語らせていただきたい。

コンテンツ駆動

アプリケーションにフォーカスしたウェブフレームワークでは実装する意味がないようなパフォーマンス向上に取り組んでいます。

本サイトでやりたかったことは、「ログイン後のダッシュボードを作ること」ではなく、「プロフィール・作品・資格・更新履歴・ブログといった情報を、読者に分かりやすく届けること」だった。だからこそ設計の出発点も、状態管理やクライアントサイドのルーティングではなく、「このページで何を見せるか」を考えることであった。

実際に作ってみると、Astroはファイルベースのページ分割と相性がよく、about・works・blog・certificationsのように、コンテンツの塊ごとにページを増やしていく感覚が自然で分かりやすかった。スキルカテゴリやUI作品詳細のように、データから静的ページを量産する場面でも getStaticPaths() が素直に使える。トップページでは、ただリンクを並べるだけでなく、Miro風のボードで導線や更新履歴を「見せるコンテンツ」として扱ったりもした。

もちろん、ブログ詳細のようにクエリパラメータとクライアント取得で本文を載せる箇所もあり、SEO向けの初期HTMLが薄い、というトレードオフはある。それでも、「アプリを作る前提」から入るフレームワークより、「コンテンツを届ける前提」から入るAstroの方が、自分のやりたいことと噛み合っていた。公式の言う「アプリ向けフレームワークでは意味が薄いパフォーマンス最適化」が、ポートフォリオではそのまま価値になった、というのが率直な所感である。

サーバーファースト

サーバーファーストという言葉を最初に見たときは、「常にサーバーで動くSSRアプリを作るのか」と少し誤解していた。本サイトで実感したのは、もう少し素朴な話で、まずHTMLをビルド時に確定し、ブラウザはそれを読むという順序がデフォルトになっている、ということだ。

公開面の骨格は、レイアウト・ヘッダー・メタ情報ごと静的HTMLとして出力し、本番は dist/ をFTPで配信する構成にしている。つまり、訪問者が最初に受け取るのは「組み立て前の空の箱」ではなく、「すでに描画されたページ」だ。一方で、更新履歴一覧やブログ一覧、管理画面のようにインタラクションが必要な部分だけ、Vueのislandとして client:load を付けている。

この切り分けが、自分にとってはとても分かりやすかった。Next.jsやNuxtのように「SPAにSSRを足す」感覚というより、「静的HTMLが本体で、島だけブラウザで動く」MPA寄りのモデルだ。共有用のWebサイトなら、頭の中のモデルとして素直に構築ができた。

ビルド時にAPIを叩いて成果物を作る使い方もしている。たとえばYouTube詳細は ?slug= 形式のため、HTMLをslugごとに静的生成するのではなく、ビルド時にslug一覧を取得して専用sitemapを出す、という補完をしている。サーバーファーストを「全部サーバーレンダリング」と捉えず、「重い処理や初期表示を、可能な限り訪問者の端末から遠ざける」と捉えると、本サイトの実装とも一致する。

デフォルトで高速

「デフォルトで高速」は、派手な最適化テクニックの話というより、遅い作り方をしにくいという話だと感じた。 Astroでは、ページの静的な部分はJavaScriptなしで成立する。ヘッダー、フッター、パンくず、説明中心のページは、そのままで読めるHTMLとなっている。インタラクションが必要な箇所だけVueをhydrateするので、「最初から全部のコンポーネントがクライアントで動く」前提にはならないのだ。

本サイトでも、速さのために特別な魔法をたくさん書いたというより、送らない選択を積み重ねました。Google AnalyticsはPartytown経由でメインスレッドの外へ逃がし、コメント欄はボタンを押したときだけGiscusを読み込むようにしています。トップのMiro風ボードも、Vueのislandにはせず、Astroコンポーネント内の軽量なscriptでドラッグ操作を賄っている。

もちろん、管理画面やブログ一覧のようにislandが多い画面では、それなりにJSが載ります。この原則の恩恵を特に感じたのは、公開コンテンツ面です。「速いサイトを頑張る」のではなく、「ゼロJSから始めて、必要な複雑さだけ足す」。その順番を守っている限り、少なくとも“何もしないのに重い”状態にはなりにくい、というのが2ヶ月触っての実感です。

簡単に使える

簡単、と聞いて「本当に?」と思っていた側の人間だが、触り始めのハードルは確かに低かった。 .astro はHTMLのスーパーセットなので、「ページを1枚増やす」作業が、ほぼHTMLを書く延長で済む。プライバシーポリシーやお問い合わせのような、動きの少ないページはAstroだけで十分だった。公式の言う「複雑さへのオプトイン」を、そのまま辿った感覚がある。

複雑さが必要になったのは、絞り込み・ページング・ログイン・管理画面といった箇所だ。そこで初めて @astrojs/vue を使い、使い慣れたコンポーネント志向のUIをislandとして載せる方法で実装を行った。最初からVueやReactでサイト全体を組む必要がなく、「ここはHTMLでいい」「ここはVueが要る」と判断できるのが、学習コスト的にも精神衛生的にも助かったポイントだった。

サーバーで描画する前提だと、ブラウザ上の細かいリアクティビティの概念に最初から付き合わなくてもよい、というのも大きい。必要なときにだけクライアントの複雑さを引き受ける。専門家でなくても始められる、という公式の言葉は、少なくとも「最初の一歩」については本当だと思われる。その先で管理画面や認証まで踏み込むと話は別だが、それでも段階を踏めること自体が、簡単さの一部だと感じた。

開発者を重視

最後の「開発者を重視」は、サイト訪問者向けの速さというより、作っている側が詰まらないかの話だろうと思う。ここは、Astro単体の機能というより、Astro前提の開発体験として強く感じた。

本サイトでは、Vue・Tailwind・Partytownといったインテグレーションで拡張し、PUBLIC_ 付きの環境変数でAPIの接続先やフィクスチャ切替、GAの有無を分けている。特に効いたのが、PUBLIC_API_USE_FIXTURE=true のときにローカルJSONを返す仕組みである。API側が未完成でも、UIとPlaywrightの確認を進められるため、本番ビルドでGA IDが無いときにCIで落とす、といったガードも、レイアウト側で素直に書けた。

また、sitemapのようにエンドポイント型の成果物をビルド時に生成できるのも、「フレームワークの外でスクリプトを別途抱える」より気持ちが楽だった。型、環境変数、テスト、公式インテグレーション。目的を達成するための道具が、最初から揃っている感覚である。

Discordやコミュニティの話は全く触れていない。しかし、ドキュメントが日本語でも読めることや、やりたいことに対して「まず公式の道がある」状態は、2ヶ月間の開発をかなり支えてくれた。速いサイトを作れるだけでなく、速いサイトを作り続けやすい。それが、開発者を重視する原則の実感である。

おわりに

5原則を並べて振り返ると、本サイトがAstro向きだった理由はシンプルで、Webアプリではなく、コンテンツを共有するサイトを作りたかったからだと思います。全部をAstroの思想どおりに完璧にやれたわけではなく、クライアント取得のページや管理画面のように、原則から少し外れるところもあります。それでも、公開面の骨格を静的HTMLに置き、必要なところだけ島を載せる、という基本方針は、2ヶ月経った今も自分の中でしっくり来ています。 デザインの改善はまだまだこれからですが、Astroの設計原則と実際の実装がどう噛み合ったかは、ひとまずこの記事に残せたかなと思います。続きでは、islandの切り方やAPI連携、フィクスチャ駆動の開発まわりなど、もう少し実装寄りの話も書いていく予定です。

関連記事