[2023年6月版]Astro.js 小ネタ集 その6 JSONコレクション
前回に引き続きAstro.jsでの小ネタを紹介していきます。
ここでは Astro 2.5 で追加された JSON コレクションについてご紹介いたします。
JSON コレクション
Astro 2.5 からコレクションでJSON、yaml形式のファイルがサポートされました。
これでタグとカテゴリとアイコンのパス、などのようなメタデータだけの集合をコレクションとして扱えるようになりました。
個人ブログでは"タグ"の定義にJSONコレクションを使っています。
ここでは "タグ" コレクションの使用方法を解説いたします。
1. 準備
まず、"タグ" コレクションの型をconfig.ts
に定義します。
...
const tags = defineCollection({
type: 'data',
schema: z.object({
title: z.string(),
icon: z.string(),
}),
});
...
export const collections = {
tags,
blog,
};
このようにJSONやYAMLのコレクションは type: 'data'
を指定します。
ここでは title
とicon
属性を持つオブジェクトとして定義します。
2. コレクションに追加
続いて、この定義に合わせてcontent以下のようなJSONファイルを作成します。
{
"title": "Redis",
"icon": "redis"
}
個人ブログではURLの一部にも使用されるタグの"キーワード"に対する画面上の表示で使用されるメタ情報をこのような形で定義、管理しています。
3. ページでの利用
そして、実際の astro ファイル上では以下のようにブログ記事のメタ情報と併せてJSONコレクションのエンティティを取得しています。
import { getCollection, getEntry } from 'astro:content';
...
const tags = await Promise.all([...(await getCollection('blog'))
.flatMap((blog) => blog.data.tags)
.reduce((uniq, tag) => uniq.add(tag), new Set<string>())]
.map(async (tag) => {
const e = await getEntry('tags', tag);
return e ?? {
id : tag,
collection: 'tags',
data: {
title : tag,
icon : ``,
}
};
}));
(await getCollection('blog')).flatMap((blog) => blog.data.tags)
でブログ記事に含まれるタグのリストを取得しています。
ブログにタグのリストがついているので、ブログのリスト(=タグのリストのリスト)からただのタグのリストに直すために flatMap
を使用しています。
続いて .reduce((uniq, tag) => uniq.add(tag), new Set<string>())
でリストをSet
にすることでタグの重複を除去します。
さらにSet
はこのままでは .map
などのメソッドが使えないので、[... タグのSet]
の形式でリストに展開します。
そして、await getEntry('tags', tag)
で タグ名.json
を読み込みます。ファイルがなければ、{id:tag, collction: 'tag', ...}
というコレクションのエンティティをその場で生成してタグのメタ情報リストを作成しています。
後はブログのコレクションと同じように tags[0].data.title
など値をHTMLに埋め込めばOKです。
ちなみに、.map(async ...)
を使用すると、この戻り値はPromiseの配列(Promise<T>[]
)となりますので、最初の Promise.all()
でPromiseの配列(Promise<T>[]
)を配列(T[]
)にしています。ややこしい。。。
今回はここまでといたします。
Discussion