BLOG

AstroのContent Collectionsでブログをつくる

Written by ogoe

INDEX

Content Collectionsは.md.mdxを型安全に管理するためのAstroの機能です。[email protected]で追加されました。

投稿日やタイトルなど、各ファイルで使用するデータに型を定義をすることで、型が間違っていたら実行時やビルド時にエラーが出て安全、というわけです。

ここではContent Collectionsを用いた簡単なブログの構築手順をご紹介します。

インストール

npm create astro@latest

以下項目を尋ねられるので選択はお好みで。

How would you like to start your new project?
Where should we create your new project? // プロジェクトのディレクトリ

How would you like to start your new project? // テンプレートの有無
● Include sample files (recommended) // サンプルファイルを含める(推奨)
○ Use blog template // ブログテンプレートを使うEmpty // 空

Install dependencies? (recommended) // 依存関係のインストールの有無(推奨)
● Yes ○ No

Do you plan to write TypeScript? // TypeScriptを書くか
● Yes ○ No

use How strict should TypeScript be? // TypeScriptの厳格さStrict (recommended) // 厳格(推奨)
○ Strictest // もっとも厳しい
○ Relaxed // リラックス

git Initialize a new git repository? (optional) // gitリポジトリの初期化の有無
● Yes ○ No

How would you like to start your new project?にてUse blog templateを選択することでもブログの構築が可能です。

インストールが終わったら、cdコマンドで作ったディレクトリに移動して以下コマンドを入力するとローカルサーバーが起動します。

npm run dev

コンテンツを格納するディレクトリをつくる

Content Collectionsではコンテンツを管理するためにsrc/contentディレクトリを使用します。

なおsrc/contentディレクトリは予約されているので、Content Collections以外の用途で使用することはできず。

srcディレクトリの中にcontentディレクトリをつくり、この中に管理したいコンテンツのコレクション名を命名したディレクトリをつくります。

ここではblog1つですが、コレクションはいくらでも追加できます。

src
  └ content
    └ blog

コレクションのディレクトリを追加後、ローカルサーバーを立て直すとルートに.astroディレクトリが自動で追加されます。

.astroディレクトリにはContent Collectionsのためのメタデータが格納されます。

このディレクトリにまつわる心配はご無用で、実行時やビルド時にAstroが自動で更新してくれます。

.gitignoreに追加しても問題ありません。

echo "\n.astro" >> .gitignore

コレクションを定義する

ディレクトリをつくったら今度は設定です。

コレクションがどのようなデータを持つか、どのような型かを決めます。

contentディレクトリにconfig.tsファイルをつくり以下を記述します。

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

const blogCollection = defineCollection({
  type: 'content',
  schema: z.object({
    date: z.number(),
    title: z.string(),
    description: z.string(),
    thumbnail: z.string(),
    tags: z.array(z.string()),
  }),
});

export const collections = {
  blog: blogCollection,
};

スキーマの中身はお好みで。ここでは投稿日、タイトル、ディスクリプション、サムネイル、タグを定義します。

datenumbertitlestringなど、ここで各スキーマの型を定義しています。

collectionsオブジェクトのキーに先ほど追加したコレクション名を、バリューにスキーマを定義した定数を設定することで完了です。

複数のコレクションを定義したり、サードパーティ製のコレクションスキーマを使用したり、などいろいろできるようです。詳細はドキュメントまで。

src/content/config.tsでモジュール'astro:content'またはそれに対応する型宣言が見つかりません。とのエラーが出た場合は、ローカルサーバーを立て直すと解消されます。

コンテンツをつくる

ディレクトリも設定も終わればお次はコンテンツです。

コンテンツには.md.mdxなどが使えます。ここではなにかと便利な.mdxを使用します。

先ほど定義したコレクションのスキーマをフロントマター内で指定し、コンテンツを記述します。

ファイル名はお好みで。ここでは投稿日にします。

// src/content/blog/230607.mdx
---
date: 2023-07-07
title: 'AstroのContent Collectionsでブログをつくる'
description: 'AstroのContent Collectionsはマークダウンを型安全に管理するための機能です。Content Collectionsを用いたブログの構築手順をご紹介します。'
thumbnail: 'astro_thumb.jpg'
tags: ['Astro']
---

// MDX内では各スキーマの値を{frontmatter.[キー]}で取得できる
# {frontmatter.title}

<img src={frontmatter.thumbnail} alt={frontmatter.title} />

Content Collectionsは`.md`や`.mdx`を型安全に管理するためのAstroの機能です。[email protected]で追加されました。

MDXの設定

MDXはMarkdown with JSXの略称で、その名の通りマークダウンの中でJSXが記述できます。

そのため、コンテンツ内にAstroコンポーネントを呼び出すことも可能です。詳細はドキュメントまで。

Astroで.mdxを使うために@astrojs/mdxをインストールします。

npx astro add mdx

インストールが完了したら適用します。

// astro.config.mjs
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  integrations: [mdx()],
});

お使いのエディターがVS Codeの場合、MDXをサポートさせるための設定をします。

// .vscode/settings.json
{
  "files.associations": {
    "*.mdx": "markdown"
  }
}

MDXの設定はこれにて完了です。

コンテンツページをつくる

コンテンツができたのでページに表示させます。

pagesディレクトリの中に[...slug].astroファイルをつくり、以下を記述します。

// pages/blog/[...slug].astro

---
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

export async function getStaticPaths() {
  const blogEntries = await getCollection('blog');
  return blogEntries.map((entry) => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}

const { entry } = Astro.props;
const { Content } = await entry.render();
---

// [...slug].astroファイル内では各スキーマの値を{[プロップス].data.[キー]}で取得できる
<Layout title={entry.data.title} description={entry.data.description}>
  <Content />
</Layout>

src/content/blog/230607.mdxをつくった場合、localhost:xxxx/blog/230607が動的にルーティングされます。

ローカルサーバーを起動してコンテンツのURLを入力するとコンテンツが表示されます🎉

コンテンツ一覧ページをつくる

残るは一覧ページです。

コンテンツ一覧を表示させたいファイルに以下を記述します。

// pages/blog/index.astro
---
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

const blogEntries = await getCollection('blog');
---

<Layout title='' description=''>
  <ul>
    {
      blogEntries.map((blogPostEntry) => (
        <li>
          <a href={`/blog/${blogPostEntry.slug}`}>
            <img src={blogPostEntry.data.thumbnail} alt={blogPostEntry.data.title} />
            <p>{blogPostEntry.data.title}</p>
          </a>
        </li>
      ))
    }
  </ul>
</Layout>

これまたローカルサーバーを起動してつくったコンテンツのURLを入力するとコンテンツが表示されます🎉

おわりに

過ちを犯せばすぐに該当箇所のエラーが出るのでトラブルシューティングも安心。

SSGにも向き不向きがありますが、つくるサイトにハマればうまいこと開発・運用できるのではないでしょうか。

参考

Content Collections 🚀 Astro Documentation

Markdown & MDX 🚀 Astro Documentation

@astrojs/mdx 🚀 Astro Documentation

What is MDX? | MDX