このブログの作り方

ポートフォリオに /blog を足しました。 技術記事は Zenn にも書いているのですが、そちらでは書けないものを置く場所が欲しくなったからです。

書けないもの、というのは表現のことです。 「このテストは実行にこれくらい時間がかかっていて、こう変えたらこうなった」みたいな話は、 文章と表で説明するより、動く図を1つ置いたほうが伝わることがあります。 自分でソースを持っているサイトなら、記事ごとに好きなものを書けます。

仕組み

表現の自由度を最優先にしたかったので、Markdown や MDX ではなく 記事1本 = 1つの .astro ページ にしました。 記事ファイルの中に <script><style> も SVG も直接書けます。

ただ、そうすると一覧ページや絞り込みに必要なメタデータ(タイトル・日付・カテゴリ)を 集める方法が要ります。ここは素直に、メタデータだけを別ファイルに分けました。

1

src/data/blog.ts に1行足す

id・タイトル・日付・カテゴリを書く。ここが記事メタデータの唯一の情報源になる。

2

src/pages/blog/{id}.astro を書く

自分の id で getPost() を引いてレイアウトに渡したら、あとは中身を自由に書くだけ。

3

一覧とカテゴリページは自動で追従する

/blog と /blog/category/{id} は blog.ts だけを読んでいるので、記事側では何もしなくていい。

記事を1本書くときの流れ

メタデータはここに集約する

// src/data/blog.ts
export const posts: Post[] = [
  {
    id: 'hello-blog',           // = /blog/hello-blog
    title: 'このブログの作り方',
    description: '...',
    publishedAt: '2026-08-03',
    categories: ['astro', 'dev'],
  },
]

記事本体は普通の .astro ページ

// src/pages/blog/hello-blog.astro
import BlogArticle from '../../layouts/BlogArticle.astro'
import BarChart from '../../components/blog/BarChart.astro'
import { getPost } from '../../data/blog'

const post = getPost('hello-blog')
---
<BlogArticle post={post}>
  <p>本文。ここから先は普通の .astro なので、</p>
  <BarChart data={[...]} caption="好きな図をそのまま置ける" />
</BlogArticle>

一覧ページが記事コンポーネントを import しない、という点だけは意図的です。 もし一覧側で全記事を読み込んでメタデータを取り出す作りにすると、 記事ごとに書いた <script> が一覧ページのバンドルにまで入ってきてしまいます。 メタデータを別ファイルに切った理由の半分はこれです。

記事の中で使えるもの

よく使いそうな図は src/components/blog/ にコンポーネントとして置いています。 まだ最低限だけで、書きながら足していく予定です。

棒グラフ

数値の比較用。スクロールして画面に入ったタイミングでバーが伸びます。

手動実行
42 分 1人日
自動化前
28 分
自動化後
6 分
※ 数値はコンポーネントの表示例で、実測値ではありません

手書きの図

決まった形に収まらないものは <Figure> に SVG をそのまま入れます。 下の図は線が引かれるアニメーションを CSS で書いたものです。

書く CI 公開
Figure の中身は完全に自由。これは stroke-dashoffset で線を描いている

補足ブロック

これから

今のところ置いてあるのは棒グラフ・手順図・補足ブロック・コード・自由な図の5つだけです。 記事を書いていて「これが欲しい」と思ったものを、その都度足していこうと思っています。

普段は Playwright での E2E まわりを触っているので、そのあたりの話から書いていく予定です。