投稿日
最終更新日

Astroのブログテンプレートを選んだときに知っておくべきこと

対象読者

はじめに、この記事の想定読者は以下のような人です。

なお、執筆時点のAstroのバージョンは5.15.3です。

Astroのブログテンプレートでは、md/mdxファイルにlayoutが指定されていない

Astroを学ぶにあたってAstroのチュートリアルを最初にやったのですが、チュートリアルでは.mdファイルにlayoutを指定しないとhtmlやheadなどのタグの無いページが出力されてしまうことを学びました。具体的には以下のようになります。

post-2.mdx
---
title: title
author: Astro学習者
description: "test"
image:
url: "https://docs.astro.build/assets/arc.webp"
alt: "Astroのアークのサムネイル。"
pubDate: 2022-07-08
tags: ["astro", "ブログ", "公開学習", "成功"]
---
## h2の見出し
コンテンツ

これはチュートリアルからとってきた.mdファイルを少し修正したものです。 このレイアウトの無いバージョンの.mdをローカルサーバに公開したときのソースコードの骨組みは次のようになります。

Terminal window
<!DOCTYPE html><meta charset="utf-8">
<script type="module" src="/@vite/client"></script>
<script type="module" ...></script>
<script>...</script>
<h2 id="h2の見出し">h2の見出し</h2>
<p>コンテンツ</p>

h2の見出しとコンテンツがh2タグとpタグで囲まれて出力されている箇所に注目してみてください。html/head/bodyなどのタグがありませんね。 チュートリアルの段階では、.mdファイルのフロントマター(---と---で囲まれている部分)にlayout: ../../layouts/MarkdownPostLayout.astroなどと指定して、そこでhtml部分などを追加して出力するという手順になっていました。 しかし、ブログテンプレートの.mdファイルはsrc/content/blogディレクトリに置かれていて、チュートリアルと異なりlayoutが指定されていません。 しかし、ちゃんとhtmlとして出力されています。そこで、これは何故?と調べてみました。

.mdや.mdxを読み込む場所を決めているsrc/content.config.tsについて

まず、自分のAstroのルートディレクトリでfind | grep -dskip .mdなどとして.mdを探してみるとnode_modulesとsrc/content/blogがヒットします。nodeモジュールは関係なさそうなのでこのsrc/content/blogを覗いてみると実際にnpm run devしてlocalhost:4321に表示されるブログ記事がここにおいてあることがわかります。

次に、find | xargs grep -dskip src/contentの結果を眺めていると.astro/content.d.tsというファイルでexport type ContentConfig = typeof import("../src/content.config.ts");という行が見つかり、src/content.config.tsをみるとloader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),という行が見つかりました。ビンゴ!

なお、.astroというディレクトリは自動生成されるディレクトリなので、content.config.tsは固定だと思った方がよいと思います。

content.config.tsがsrc/contentから.mdや.mdxを取得する設定をしているファイルだとわかりました。

古いバージョンのAstroではsrc/contentは予約されていて、このファイルもsrc/content/config.tsという名称だったみたいですが、現在はsrc/pages/だけしか予約されていません(このリンク先のヒントに書いてあります)

しかし、ここで行き詰まったので公式の情報を探してみました。次の段落で解説します。

レイアウトを決めているファイル

結論からいうとレイアウト情報は、公式のこのページにありました。

src/pages/blog/index.astroがブログページ一覧 src/pages/blog/[…slug].astroが個別のブログ記事 を設定しているファイルになります。

index.astroのフロントマター抜粋
---
import { Image } from 'astro:assets';
import { getCollection } from 'astro:content';
import BaseHead from '../../components/BaseHead.astro';
import Footer from '../../components/Footer.astro';
import FormattedDate from '../../components/FormattedDate.astro';
import Header from '../../components/Header.astro';
import { SITE_DESCRIPTION, SITE_TITLE } from '../../consts';
const posts = (await getCollection('blog')).sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
);
---

ここからわかるように、BaseHead/Footer/Headerなどのレイアウトコンポーネントが使われています。

[...slug].astro
---
import { type CollectionEntry, getCollection, render } from 'astro:content';
import BlogPost from '../../layouts/BlogPost.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.id },
props: post,
}));
}
type Props = CollectionEntry<'blog'>;
const post = Astro.props;
const { Content } = await render(post);
---
<BlogPost {...post.data}>
<Content />
</BlogPost>

こちらは[…slug].astroの中身です。layouts/BlogPost.astroがレイアウトファイルです。これで.md/.mdxにレイアウト指定がなくても表示される仕組みが分かりました。 BlogPostの詳細は省きますが、index.astroと同じくBaseHead/Footer/Headerなどのレイアウトコンポーネントが使われています。 今後は自分のオリジナルのブログにしていくためにこのあたりのファイルを修正していくことになるかと思います。

追記:ブログテンプレートで生成したホームページのトップページに当たるsrc/pages/index.astroにlayoutはBlogPost.astroを修正してと書いてありました。この回り道をした感・・