本ブログを Astro で作ったので、Astro でブログを作る流れと所感について書きます。
Astro JS とは
公式ドキュメントで次のように説明されています。
Astro は、コンテンツにフォーカスした高速な Web サイトを構築するためのオールインワン Web フレームワークです。
なぜ他の Web フレームワークではなく、Astro を選ぶのでしょうか?ここでは…(中略)5 つの基本設計原則を紹介します。
Astro は……
- コンテンツ重視: Astro は、コンテンツが豊富な Web サイトのために設計されています。
- サーバーファースト: HTML をサーバーでレンダリングすることで、Web サイトの動作が速くなります。
- デフォルトで高速: Astro で遅いウェブサイトを構築することは不可能です。
- 簡単に使える: 専門家でなくても、Astro で何かを構築できます。
- 充実した機能と柔軟性: 100 以上の Astro インテグレーションから選択できます。
JS を含まない HTML を生成することを基本としつつ、必要があれば JS を含むページも作成できる、フロントエンドフレームワークです。汎用的に使えますが SSG に軸足を置いており、マークダウンファイルを標準で扱えるので、今回のマイクロブログの構築のようなユースケースに向いています。ドキュメントが充実していてわかりやすく、ブログを作るチュートリアル もあります。
Astro と言えば、 Vue や React などの異なるフレームワークを混在させることができる Astro アイランド という特徴的な機能がありますが、自分はまだ触れておらずよくわかりません。面白い機能だとは思うのですが、その機能を使うほど凝ったユースケースがまだ無い状態です。部分的に JS が必要になった場合に、好きなフレームワークやその周りのライブラリを使えると考えると便利そうですね。
(ブログを Astro に変えた - @macoshita では Astro アイランドを Hydration の観点で説明しており参考になりました。)
Astro での個人ブログの作り方
Astro でブログを作るときにおよそどんな作業が必要になるのか紹介します。実際に作り始めるときは、先程紹介したチュートリアルも良いですし、examples ディレクトリにたくさん例があるので良さげなものをピックアップしても良いと思います。
1. プロジェクトを作る
npm create astro@latest
で始めます。ちなみにこれから紹介するコード例では最終的なディレクトリ構成がこんな感じになります。
.
├── README.md
├── astro.config.mjs
├── package-lock.json
├── package.json
├── public
├── src
│ ├── env.d.ts
│ ├── layouts
│ │ └── BlogPostLayout.astro
│ └── pages
│ ├── index.astro
│ └── posts
│ ├── post-1.md
│ └── post-2.md
└── tsconfig.json
Astro は Next.js のようにファイルベースでルーティングします。src/pages
をルートに URL が決定します。
2. Markdown の記事を表示する
まずは表示する記事が必要なので、最初の記事 src/pages/posts/post-1.md
を作ります。
## Hello, Astro!
ヤッホー!
この時点で dev server を起動して /posts/post-1/
にアクセスするともう記事が表示されます。Markdown のビルドは勝手にやってくれるのです。簡単で良いですね。
しかし、このままでは記事のタイトルや作成日を表示できませんので、次のように編集します。
---
title: "はじめての記事だよ"
pubDate: 2023-02-05
layout: "../../layouts/BlogPostLayout.astro"
---
# Hello, Astro!
ヤッホー!
---
で囲まれたところに frontmatter と呼ばれる記事のメタ情報を書くことができます。この属性は自由に付与できるので、例えば draft
属性を定義して下書き記事の機能を作ることもできます。また、layout
属性を指定することで記事ページのレイアウト を作ることができます。src/layouts/BlogPostLayout.astro
を作ります。
---
const { frontmatter } = Astro.props;
---
{/* main section 以外の HTML は省略 */}
<main>
<article>
<h1 class="title">{frontmatter.title}</h1>
<time>{frontmatter.pubDate}</time>
<hr />
<slot />
<!-- Markdownコンテンツはここに挿入されます -->
</article>
</main>
<style>
h1 {
font-size: 20px;
}
</style>
Astro では、---
で囲まれたところに JS を書いて、その下に HTML を書くというフォーマットでコードを記述します。少し Vue に似ていますね。先程 Markdown に定義した frontmatter は Astro.props
から受け取ることができるので、あとは JSX でページを作るだけです。CSS は HTML の好きな場所に <style>
タグを書けば良く、自動的にスコープされたスタイル となります。
レイアウトの仕組みを使えば、記事ページだけでなく、サイト全体の head、header、footer 等も共通化できます。今回は触れませんが、基本的には同じ要領でコンポーネントも自由に作ることができます。
3. Markdown の記事を並べる
記事ページができたので、記事一覧ページを作ります。src/pages/index.astro
を作成します。
---
// 記事リストの取得
const posts = await Astro.glob("./posts/*.md");
---
{/* main section 以外の HTML は省略 */}
<main>
<h1>ようこそ!</h1>
<ul>
{
posts.map(({ url, frontmatter }) => (
<li>
<a href={url}>{frontmatter.title}</a>
</li>
))
}
</ul>
</main>
Astro.glob
を使うと記事ファイル一覧を取得できます。今回はそれをリストアイテムにマップしているだけです。実はこのままだと posts
の順番が日付順になっていないので、ソートして古い順に表示する必要があったりします。とはいえひとまず、 /
に記事を並べることができました。
4. SEO、RSS、アナリティクス、ファイル圧縮
自前で実装してもよいですが、Astro インテグレーション が充実しているのでそちらを使うのが簡単です。
- SEO: jonasmerlin/astro-seo | Github
- サイトマップ: @astrojs/sitemap | Astro ドキュメント
- RSS: RSS | Astro ドキュメント
- アナリティクス: @astrojs/partytown | Astro ドキュメント
- 圧縮: astro-community/astro-compress | Github
5. 目次の出力、コードのシンタックスハイライト
こちらも markdown のコンテンツをパースして自前で実装することもできますが、remark や rehype といったプロセッサのプラグインを使うと簡単に実現できます。awesome-remark や awesome-rehype を覗いてみると良さそうです。また、シンタックスハイライトは Shiki と Prism がビルトインでサポートされます。詳しくは Markdown と MDX の設定 を見てみてください。
6. デプロイ
CI で npm ci && npm run build
してお好きな場所にデプロイすれば良いです。自分は Cloudflare Pages を使ってみました。
以上です。簡単な説明ではありましたが、流れを掴んでいただければ嬉しいです。コードは GitHub に置いておきました。
所感
JSX で書け、Vue のような簡易で明瞭なフォーマットで記述できるので使いやすかったです。個人開発している haraiai のサイト も Vue から Astro に書き直しました。Markdown を最初から扱えるので お知らせ ページを簡単に構築できたのが良かったです。SSG で良いケースは意外に多いので、覚えておいて損はないと思います。今の所、JS を使うケースが発生していないのですが、もし必要になっても対応できるので安心感があります。
ブログを作るのに向いているか?
今回作ってみて、Astro がマイクロブログを作るケースに向いているかというと、もちろん向いてはいるのですが、スクラッチで書く理由は必要かなと思います。例えば、デザインをゼロから自分で作りたいとか、JS を使った追加的な機能が必要だとか、Astro を触りたいから(自分)とか。特別な理由がなければ Hugo や Gatsby が正解です。作ってみるとわかりますが、色々と細かい実装が必要です。
- デザイン、スタイリング(Markdown で出力される要素って色々あります)
- head 内の各種タグ設定
- サイトマップ、RSS
- Astro.glob でリストした記事の並び替え
- 下書き設定の記事の表示/非表示
- タグ、カテゴリページ
- ページング
以前のブログでは Hugo を使っていましたが、既存のテーマを借りつつ fork してカスタマイズしていました。静的サイトジェネレータでもデザインやレイアウトは自由に作ることができます。
記事に MDX を使うべきか?
これは単に自分はこうした、という話なのですが。記事中の要素の共通化はあえてやらないことにしました。MDX を使うと Astro コンポーネントを記事内で用いるといったこともできるのですが、プレーンな Markdown でなくなる分、互換性が低くなるので止めました。Markdown エディタでプレビューされず書きづらくなったり、コンテンツを移管しづらくなると思いました。
さいごに
静的なコンテンツが中心なら Astro はおすすめです。コンテンツ志向で最初から Markdown を扱えるため、React や Vue で書くよりもコーディングに集中でき、素早くサイトを構築できます。目的がはっきりしている分、フレームワークもシンプルですし、プラグインが豊富なので痒いところにも手が届く印象です。Astro アイランド や SSR もありますので、プログレッシブに複雑なことも出来るかと思いますが、それらも追々試せたらなと思っています。