メインコンテンツへスキップ
#Web制作 約9分で読めます

Astro 5.2 の新機能と Server Islands で静的サイトの動的パーツを速くした話

Astro 5.2 で追加された astro:config や trailing slash 修正を Server Islands と組み合わせて使った実体験。パフォーマンス計測の結果と注意点をまとめた。

クライアントのECサイトで「商品一覧は静的でいいけど、カートとレビューだけリアルタイムにしたい」という要件が出たとき、最初に試したのが Astro の Server Islands だった。Astro 5.0 で正式リリースされた機能で、5.2(2025年1月リリース)で周辺の改善が入ったタイミングでプロジェクトに導入した。結果から言うと、ページの静的シェルが CDN から返るようになって LCP は体感で3〜4割速くなった。ただ、地味にハマったポイントもある。

Server Islands が解決する「全部 SSR 問題」

従来の SSR だと、ページ内にログインユーザーのアバターが1個あるだけで、ページ全体がオンデマンドレンダリングになる。CDN キャッシュが効かなくなり、静的でいいはずの商品説明や画像まで毎回サーバーで生成される。これが遅い。

Server Islands は、この「動的なパーツ」だけを切り出す仕組み。ページ本体は静的 HTML として CDN にキャッシュし、ユーザー固有のコンポーネント(カート、アバター、レビュー投稿フォームなど)だけを後から非同期でサーバーレンダリングして差し込む。

使い方はシンプルで、コンポーネントに server:defer をつけるだけ。

---
import CartButton from '../components/CartButton.astro';
import Avatar from '../components/Avatar.astro';
---
<nav>
  <Avatar server:defer>
    <div slot="fallback" class="w-8 h-8 rounded-full bg-gray-200" />
  </Avatar>
  <CartButton server:defer>
    <span slot="fallback">🛒</span>
  </CartButton>
</nav>

slot="fallback" で指定した要素が、島のレンダリングが完了するまでプレースホルダーとして表示される。ユーザーはページの大部分を即座に見られて、動的パーツだけが後から差し替わる。

各島が独立してレンダリングされるのもポイント。レビュー取得が遅くても、カートの表示には影響しない。client:visible などのクライアントサイド island とは根本的に違って、JavaScript をブラウザに送らずにサーバーで HTML を生成して返す。JS バンドルが増えない。

5.2 で地味に効いた改善

Server Islands 自体は 5.0 の機能だが、5.2 で入った変更が実運用で助かった場面がいくつかある。

trailing slash の自動リダイレクト。 5.2 から、astro.config.mjstrailingSlash 設定に応じて、オンデマンドレンダリングのルートが自動で正しいパスにリダイレクトされるようになった。GET は 301、その他は 308。Server Islands のエンドポイントも内部的にはオンデマンドレンダリングなので、CDN 側で末尾スラッシュの不一致によるキャッシュミスが起きにくくなった。手動で対処していたのが不要になったという話で、劇的な高速化ではない。ただ、キャッシュヒット率が安定したのは数値に出た。

外部リダイレクトのサポート。 config から直接 https:// への転送が書ける。

// astro.config.mjs
export default defineConfig({
  redirects: {
    "/old-shop": "https://new-shop.example.com",
    "/news": { status: 302, destination: "https://example.com/news" }
  }
});

astro:config モジュール(5.2 では experimental、5.7 で安定化)。プロジェクト内のどこからでも型安全に設定値を参照できる仕組みで、Server Islands のコンポーネント内から site の URL や trailingSlash の設定を取得するのに使った。以前は Astro.site をあちこちで参照していたのが、import { site } from 'astro:config/server' で統一できる。

Tailwind CSS v4 対応。 @tailwindcss/vite プラグインを直接 Astro に統合できるようになって、astro add tailwind で v4 がセットアップされる。旧来の @astrojs/tailwind integration は非推奨になった。Server Islands の fallback スロットのスタイリングを Tailwind で書いていたので、v4 の CSS-first な設定に移行できたのは開発体験として良かった。

パフォーマンス計測で見えたこと

導入前(全ページ SSR)と導入後(静的シェル+Server Islands)で Lighthouse を回した。モバイルのスコアで比較している。

LCP は目に見えて改善した。静的シェルが CDN から返るので当然といえば当然で、オリジンサーバーへのラウンドトリップが初回描画から消える。動的な島は後から差し替わるが、LCP の対象はページの主要コンテンツ(商品画像や説明文)なので、そこは静的 HTML として即座に表示される。

CLS(レイアウトシフト)は注意が要る。 fallback のサイズと実際のコンポーネントのサイズが合っていないと、差し替え時にガクッとずれる。最初やらかして CLS が悪化した。fallback には実際のコンポーネントと同じ高さ・幅の placeholder を用意するのが鉄則。スケルトンスクリーンを作るのが面倒なら、最低限 min-height だけは合わせておく。

もう一つ、Server Islands の props は URL のクエリ文字列に暗号化されて渡される(GET リクエスト)。つまり props が小さければブラウザや CDN でキャッシュが効く。逆に props が大きすぎると POST にフォールバックして、キャッシュが効かなくなる。ブラウザの URL 長制限(だいたい2048バイト)を超えると POST になる仕様。商品IDだけ渡すような設計なら問題ないが、大きなオブジェクトを props で渡そうとすると落とし穴になる。

ハマったところと対処

Server Islands はビルド時にコンポーネントごとの専用ルートを生成する。そのため、adapter(Cloudflare、Vercel、Netlify など)が必須。静的ホスティングだけでは動かない。当たり前だが、最初「なぜ build が通らないのか」と数十分悩んだのは白状しておく。

ローリングデプロイやマルチリージョン構成の場合、暗号化キーの管理が必要になる。Astro はビルドごとにキーを生成するので、複数のデプロイが並行すると古いキーで暗号化された props を新しいビルドが復号できない。astro create-key でキーを生成して ASTRO_KEY 環境変数に固定する運用にした。これを忘れるとデプロイ直後に島が壊れる。

Server Islands の中から現在のページ URL を取得するには Referer ヘッダーを見る必要がある。Astro.url ではなく Astro.request.headers.get('Referer') を使う。島は独立したエンドポイントとして動くので、Astro.url は島自体のエンドポイント URL を返す。ここは直感に反するので最初バグだと思った。

---
// Server Island 内でページ URL を取得する
const referer = Astro.request.headers.get('Referer');
const url = new URL(referer);
const productId = url.searchParams.get('id');
---

今から始めるなら

2026年7月時点で Astro は 7.0 まで進んでいる。5.2 の機能はすべて現行バージョンに引き継がれているので、新規プロジェクトなら最新版を使えばいい。astro:config は 5.7 で安定化済み、Server Islands は 5.0 からずっと stable。Astro 7.0 ではコンパイラが Rust に書き直されてビルド自体も速くなっているので、Server Islands を使うかどうかに関係なく恩恵がある。

Server Islands は「ページの大部分が静的で、一部だけ動的」という要件にぴったりハマる。逆に、ページ全体がユーザー固有のダッシュボードのような場合は、素直に全体を SSR するほうがシンプル。使いどころを間違えなければ、CDN キャッシュと動的レンダリングのいいとこ取りができる、Astro らしい機能だと思う。

参考リンク

#Astro #Server Islands #パフォーマンス #astro:config #Tailwind CSS v4
シェア