シリーズ目次 / 前章: 07. AstroでMarkdownとMDXを使いこなす / 次章: 09. Astroのレンダリングモードとアダプター
Table of contents
Open Table of contents
この章のねらい
第1章で、Astroは既定でJavaScriptを送らないと書きました。では検索ボックスや画像カルーセルのような動く部品はどうするのか。
そこで出てくるのがアイランドアーキテクチャです。考え方と、実際の書き方を見ます。
アイランドとは何か
アイランドアーキテクチャは、ページの大部分を静的HTMLとして描き、対話性が必要な部分にだけ小さなJavaScriptを配置する設計パターンです。
名前のとおり、静的HTMLという「海」の上に、動く部品が「島」として点在するイメージです。
Astroには2種類のアイランドがあります。
| 種類 | 実行場所 | 用途 |
|---|---|---|
| クライアントアイランド | 閲覧者のブラウザ | ボタン、フォーム、カルーセルなどの対話UI |
| サーバーアイランド | サーバー | ログイン状態やカート内容など、都度変わる表示 |
ページの上での位置づけを描くと、次のようになります。
部分的なハイドレーションの利点
公式ドキュメントは、部分的なハイドレーション(必要な部分だけを動かすこと)の利点をこう挙げています。
- 性能: 必要なコンポーネントの分だけJavaScriptを読み込むため、無駄な転送が起きない
- 並列読み込み: 複数のアイランドが互いに独立して読み込まれる。重い島が軽い島を待たせない
- 選択的な描画: どこを動かすかを開発者が明示的に決められる
- 体験の向上: 読み込み中はフォールバック表示を出せるため、レイアウトのずれが起きにくい
用語: ハイドレーション(hydration)とは、サーバーが生成した静的HTMLに対してJavaScriptを結びつけ、クリックなどの操作に反応できる状態にする処理のことです。「乾いたHTMLに水を与える」という比喩から来ています。
client:* ディレクティブ
UIフレームワークのコンポーネントをAstroに置いただけでは、静的HTMLとして描画され、JavaScriptは削除されます。対話的にするには、client:* ディレクティブを付けます。
---
import Counter from "../components/Counter.jsx";
---
<!-- 静的HTML。ボタンを押しても何も起きない -->
<Counter />
<!-- ページ読み込み後すぐに対話可能になる -->
<Counter client:load />
ディレクティブの種類と挙動は次のとおりです。
| ディレクティブ | 読み込む時点 | 向いている場面 |
|---|---|---|
client:load | ページ読み込み直後 | 画面上部にあり、すぐ操作される可能性が高いもの |
client:idle | ブラウザが空き時間になったとき | 重要だが急がないもの |
client:visible | その部品が画面内に入ったとき | ページ下部のコメント欄、地図など |
client:media={条件} | メディアクエリに一致したとき | モバイル専用メニューなど |
client:only={"react"} | サーバー描画を行わず、ブラウザでのみ描画 | window など、ブラウザ固有のAPIに依存するもの |
選び方の指針
まず client:visible から検討して、画面上部にあって即座に反応が要るものだけ client:load にしてください。全部に client:load を付けたら、Astroを使っている意味がなくなります。
client:only は、サーバー描画を完全に諦める指定です。サーバーには window も document もないので、それを前提としたライブラリを使うときの逃げ道になります。ただし初期表示が空になります。多用しないでください。フレームワーク名("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 / SolidJS | children プロパティ |
| 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" の内容が表示されるため、画面がガクッとずれる現象も防げます。
表示が差し替わるまでの流れは次のとおりです。
クライアントアイランドがブラウザ側の島、サーバーアイランドがサーバー側の島。サーバーアイランドを使うには、次章で扱うアダプターの設定が要ります。
使い分けの判断
実装に入る前に、上から順に確かめてください。足りた時点で止めれば無駄が出ません。
- そもそもJavaScriptが要るか:CSSだけで実現できないか(アコーディオンや画像切り替えは、CSSやHTMLの標準機能で足りることがあります)
- 素の
<script>で足りるか:クリックでクラスを付け替える程度なら、フレームワークは不要です - 状態管理が複雑か:ここまで来て初めて、React等のアイランドを検討します
- サーバーの情報が要るか:ユーザー固有の表示なら、サーバーアイランドを検討します
要点
- アイランドアーキテクチャは、静的HTMLの中に対話性が必要な部分だけを島として配置する設計である。
- UIフレームワークのコンポーネントは、
client:*を付けて初めて対話的になる。 - 既定の選択肢は
client:visible。すぐ操作されるものだけclient:loadにする。 - Propsには関数を渡せない。childrenの受け取り方はフレームワークごとに異なる。
server:deferによるサーバーアイランドで、静的な高速配信と個別表示を両立できる。
参考資料
- Astro Islands — Astro Docs
- Front-end frameworks — Astro Docs
- Server Islands — Astro Docs
- Template Directives Reference — Astro Docs
シリーズ目次 / 前章: 07. AstroでMarkdownとMDXを使いこなす / 次章: 09. Astroのレンダリングモードとアダプター