🌟

Astro 5.0の新機能(Content Layer API / Server Island)

2024/12/09に公開

この記事は、Astro 5.0の新機能「Content Layer API」と「Server Island」の解説です

ブログ記事
https://astro.build/blog/astro-5/
アップグレードガイド
https://docs.astro.build/en/guides/upgrade-to/v5/

雑感

Astroは、コンセプトのCoreにNo JavaScript / Less JavaScriptで、
ビルド後にJavaScriptが少なくなること=パフォーマンスが良くなる、という設計思想がベースにあります
静的な画面であることを基本とし、JavaScriptを使ったインタラクティブなUIが必要なところはAstro Island、サーバーからのデータ取得が必要なコンポーネントはServer Island
というふうに、JavaScriptを減らす方針と考えています

Content Collection APIから、Content Layer APIへ

Content Collectionは、ローカルファイル(mdxやjson)を管理する方法として登場しました
Astro 5.0以降は、ローカルファイルに限らず、リモートのAPIから取得したデータも、Contents Collectionとして扱えるようになりました

Content Layer API

https://astro.build/blog/future-of-astro-content-layer/
https://astro.build/blog/content-layer-deep-dive/

実装方法

1. Content Collectionの定義

src/content.config.jsか、src/content/config.tsにContent Collectionを定義します
loaderにfetchする関数を書き、schemaにzodを使ってContent Collectionのデータ型を定義します

src/content.config.js
// src/content.config.ts
import { defineCollection, z } from 'astro:content';

const news = defineCollection({
  loader: () => fetch('https://api.example.com/news').then(res => res.json()),
})
  schema: z.object({
     id: z.string(),
    title: z.string(),
    slug: z.string(),
    publishDateTime: z.string(),
})
;

export const collections = { news }

https://docs.astro.build/en/guides/content-collections/#defining-collections

2. 記事一覧で、Contents Collectionを表示

news/index.astro
---
const newsList = await getCollection("news");
---

{
    newsList.map((item) => (
      <li>
        <a href={`/news/article/${item.data.path}`}>
          <p>{item.data.publishDate}</p>
          <p>{item.data.title}</p>
          </div>
        </a>
      </li>
    ))
  }

ここのnewsListの型は、CollectionEntry型を使って、type NewsList = CollectionEntry<"newsCollection">[]となります

https://docs.astro.build/en/reference/modules/astro-content/

Server Island

Astroの主要機能である、アイランドアーキテクチャのコンセプトをサーバーまで拡張し、
ログインやショッピングカート部分をアイランドアーキテクチャを使って表示できるようになりました

Server Island

つまり、
「①完全に静的であり変化しないコンテンツ」「②データベースにより変化するコンテンツ」「③個々のユーザーに合わせてパーソナライズされたコンテンツ(ログイン状態が必須)」が混ざる場合、
③に合わせてCDNキャッシュできなかったものが、キャッシュできるようになります

実装例

Server Islandとしてレンダリングしたいコンポーネントにserver:deferを追記、
内包するフォールバック用コンポーネントにslot="fallback"を記述します

import Avatar from '../components/Avatar.astro';
import GenericAvatar from '../components/GenericAvatar.astro';
---
<Avatar server:defer>
  <GenericAvatar slot="fallback" /> ← fallbackコンテンツ
</Avatar>

https://docs.astro.build/en/guides/server-islands/

これに伴って、output: hybridは廃止され、
output: 'static'と、全てSSRとするoutput: 'server'の2つになりました

https://docs.astro.build/en/guides/upgrade-to/v5/#removed-hybrid-rendering-mode
https://docs.astro.build/en/reference/configuration-reference/#output

Discussion