この記事の概要
Astro ではsrc/content
にあるディレクトリは 1 つのコンテンツコレクションを表します。
コンテンツコレクションではフロントマターのスキーマを定義・検証できます。
公式ドキュメントでは記事の管理のしやすさやコンテンツコレクションを起点としたルーティングについての記載が多いです。
ただ、自分が触っている中でコンポーネント作成時も便利だと感じたので記事にしました。
CollectionEntry
型が便利
コンテンツコレクションとして 1 番よくある、記事管理を想定します。
以下のようにblog
コレクションを作成します。
(公式ドキュメントにある内容のままです。)
import { z, defineCollection } from 'astro:content';
const blogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
tags: z.array(z.string()),
image: z.string().optional(),
}),
});
export const collections = {
'blog': blogCollection,
};
ここで、関連記事コンポーネントを作るとしましょう。
以下の要素で作るとします。
- 画像
- デフォルト画像を用意しておき、設定されていない記事の場合はそれを使う
- 記事タイトル
- タグ
- たくさんあるときは折り返して表示する
こちらの内容をスキーマの型に沿って作ろうと思う際CollectionEntry
が便利です。
イメージを以下に示します。
---
import { Image } from "astro:assets";
import type { CollectionEntry } from "astro:content";
type Props = {
blog: CollectionEntry<"blog">;
}
const { blog } = Astro.props;
---
<a href={`/${blog.slug}`}>
<Image
alt=""
height="100"
width="100"
src={blog.data.image ? {blog.data.image} : "path/to/default/image"}
/>
<p>{blog.data.title}</p>
{blog.data.tags.map(tag => (
<span>{tag}</span>
))}
</a>
注目していただきたいのはblog: CollectionEntry<"blog">
です。
この記載だけで以下のような情報を取得できています。
const blog: ({
id: string;
slug: string;
body: string;
collection: "blog"
data: {
title: string;
tags: string[];
image?: string | undefind
}
})
data
の中身はsrc/content/config.ts
で定義した通りです。
それ以外にも、id や body などを一緒に取得できています。
これにより、あるコンテンツコレクションに適合した型を確実に使える、と言えそうです。
また、コンテンツコレクションを変更すればコンポーネントにも反映されます。
そのため、意図せぬ挙動や表示崩れを防げそうです。
最後に
ドキュメントを読んでいて「これってかなり安全なのでは?」と一人で盛り上がっていました。
しかし、その割には(?)公式ドキュメントではこれだけしか触れられていません。
自分の中では結構良い機能だと思ったので、この記事でもってみなさんに共有します。
追記:
「これだけ」なんて記載しましたが、すみません全然他にもありました。1
-
X にて教えていただきました。 https://x.com/_yuheiy/status/1808909812287295714 ↩