Skip to content
Cloud AI エンジニア入門ガイド
Go back

08. AstroのアイランドアーキテクチャとUIフレームワーク

この章の全体像として、アイランドとは、client:*、既定の選択、サーバーアイランドの4つを番号順に並べ、どこに動きを足すかを判断できるようになることを示した図

シリーズ目次前章: 07. AstroでMarkdownとMDXを使いこなす次章: 09. Astroのレンダリングモードとアダプター

Table of contents

Open Table of contents

この章のねらい

第1章で、Astroは既定でJavaScriptを送らないと書きました。では検索ボックスや画像カルーセルのような動く部品はどうするのか。

そこで出てくるのがアイランドアーキテクチャです。考え方と、実際の書き方を見ます。

アイランドとは何か

アイランドアーキテクチャは、ページの大部分を静的HTMLとして描き、対話性が必要な部分にだけ小さなJavaScriptを配置する設計パターンです。

名前のとおり、静的HTMLという「海」の上に、動く部品が「島」として点在するイメージです。

Astroには2種類のアイランドがあります。

種類実行場所用途
クライアントアイランド閲覧者のブラウザボタン、フォーム、カルーセルなどの対話UI
サーバーアイランドサーバーログイン状態やカート内容など、都度変わる表示

ページの上での位置づけを描くと、次のようになります。

ページの大部分は静的HTMLのままで、対話が必要な箇所だけがクライアントアイランドとして、サーバーの情報が必要な箇所だけがサーバーアイランドとして点在することを、ページの模式図と凡例で示した図

部分的なハイドレーションの利点

公式ドキュメントは、部分的なハイドレーション(必要な部分だけを動かすこと)の利点をこう挙げています。

用語: ハイドレーション(hydration)とは、サーバーが生成した静的HTMLに対してJavaScriptを結びつけ、クリックなどの操作に反応できる状態にする処理のことです。「乾いたHTMLに水を与える」という比喩から来ています。

client:* ディレクティブ

UIフレームワークのコンポーネントをAstroに置いただけでは、静的HTMLとして描画され、JavaScriptは削除されます。対話的にするには、client:* ディレクティブを付けます。

---
import Counter from "../components/Counter.jsx";
---

<!-- 静的HTML。ボタンを押しても何も起きない -->
<Counter />

<!-- ページ読み込み後すぐに対話可能になる -->
<Counter client:load />

ディレクティブの種類と挙動は次のとおりです。

clientディレクティブの指定によって、JSを読み込む時点が即時・アイドル時・表示時・条件一致時に分かれ、指定なしならJSを送らないことを示した図

ディレクティブ読み込む時点向いている場面
client:loadページ読み込み直後画面上部にあり、すぐ操作される可能性が高いもの
client:idleブラウザが空き時間になったとき重要だが急がないもの
client:visibleその部品が画面内に入ったときページ下部のコメント欄、地図など
client:media={条件}メディアクエリに一致したときモバイル専用メニューなど
client:only={"react"}サーバー描画を行わず、ブラウザでのみ描画window など、ブラウザ固有のAPIに依存するもの

選び方の指針

まず client:visible から検討して、画面上部にあって即座に反応が要るものだけ client:load にしてください。全部に client:load を付けたら、Astroを使っている意味がなくなります。

client:only は、サーバー描画を完全に諦める指定です。サーバーには windowdocument もないので、それを前提としたライブラリを使うときの逃げ道になります。ただし初期表示が空になります。多用しないでください。フレームワーク名("react""svelte")の指定は必須です。

UIフレームワークを統合する

公式インテグレーションとして、React、Preact、Svelte、Vue、SolidJS、Alpine.jsがサポートされています。導入はコマンド1つです。

npx astro add react

依存パッケージのインストールと astro.config.mjs の更新が自動で行われます。あとは、そのフレームワークのコンポーネントを普通にインポートするだけです。

---
import ReactCounter from "../components/Counter.jsx";
import SvelteChart from "../components/Chart.svelte";
---

<ReactCounter client:load />
<SvelteChart client:visible />

1つのAstroコンポーネントの中で、複数のフレームワークを同時に使えます。これは他のフレームワークにはあまりない特徴です。段階的な移行や、特定ライブラリの都合に合わせた選択が可能になります。

ただし、フレームワークのファイル同士を混ぜることはできません。.jsx の中で .svelte を読み込むといった使い方は不可です。

Propsとchildrenの注意点

Propsに渡せる値

アイランドに渡すPropsは、サーバーからブラウザへ受け渡されるため、データとして表現できる値に限られます。文字列、数値、真偽値、配列、オブジェクト、Map などは問題ありません。

一方、関数は渡せません。ハイドレーション後には使えなくなるためです。「クリック時に呼ぶ処理」をAstro側から渡す設計は避け、コンポーネント内部で完結させてください。

childrenの受け取り方

タグの中身(children)の受け取り方は、フレームワークによって異なります。

フレームワーク受け取り方
React / Preact / SolidJSchildren プロパティ
Svelte / Vue<slot /> 要素

名前付きスロットを使う場合、Astro側でケバブケース(my-slot)で書いた名前は、React系ではキャメルケース(mySlot)に自動変換されます。

Astroコンポーネントの制約

.astro コンポーネントは、フレームワークのファイルからインポートできません。.astro はHTMLを生成するためのもので、ReactやVueのレンダリングの仕組みには乗らないためです。

また、.astro コンポーネント自体に client:load などを付けることもできません(エラーになります)。ハイドレーションの対象になるのは、フレームワークのコンポーネントだけです。

サーバーアイランド

もうひとつのアイランドが、サーバーアイランドです。.astro コンポーネントに server:defer を付けると、その部分だけを本体とは切り離してサーバーで描画できます。

---
import UserGreeting from "../components/UserGreeting.astro";
---

<h1>ようこそ</h1>

<UserGreeting server:defer>
  <p slot="fallback">読み込み中…</p>
</UserGreeting>

これにより、ページ全体はキャッシュ可能な静的HTMLとして高速に配信しつつ、「ログイン中のユーザー名」のような個別の情報だけを後から差し込めます。読み込み完了までは slot="fallback" の内容が表示されるため、画面がガクッとずれる現象も防げます。

表示が差し替わるまでの流れは次のとおりです。

キャッシュ可能な静的HTMLが先に届いてフォールバックが表示され、サーバーがその部分だけを描画して後から差し込むことで、ページ全体を止めずに個別の情報を表示できる流れを三段階で示した図

クライアントアイランドがブラウザ側の島、サーバーアイランドがサーバー側の島。サーバーアイランドを使うには、次章で扱うアダプターの設定が要ります。

使い分けの判断

実装に入る前に、上から順に確かめてください。足りた時点で止めれば無駄が出ません。

  1. そもそもJavaScriptが要るか:CSSだけで実現できないか(アコーディオンや画像切り替えは、CSSやHTMLの標準機能で足りることがあります)
  2. 素の <script> で足りるか:クリックでクラスを付け替える程度なら、フレームワークは不要です
  3. 状態管理が複雑か:ここまで来て初めて、React等のアイランドを検討します
  4. サーバーの情報が要るか:ユーザー固有の表示なら、サーバーアイランドを検討します

JavaScriptが本当に必要か、素のscriptで足りるか、状態管理が複雑か、サーバーの情報が必要かを上から順に確かめ、足りた時点でそこで止めるという判断の階段を示した図

要点

参考資料


シリーズ目次前章: 07. AstroでMarkdownとMDXを使いこなす次章: 09. Astroのレンダリングモードとアダプター


Share this post:

Previous Post
09. Astroのレンダリングモードとアダプター
Next Post
07. AstroでMarkdownとMDXを使いこなす