Astro を使ってブログを再構築する: ステップバイステップガイド

Astro を使ってブログを再構築する: ステップバイステップガイド

岩佐 孝浩
岩佐 孝浩
13 min read
Astro Tailwind CSS

はじめに

Astro は、革新的な機能とパフォーマンスの向上により注目を集めている モダンな静的サイトジェネレーター (SSG) です。この記事では、Astro を使用したブログ再構築のセットアッププロセスと実装方法について詳しく解説します。

Astro の特徴

Astro は、パフォーマンスと柔軟性 に重点を置き、Web 開発を簡略化します。注目すべき 2 つの特徴は以下の通りです。

  • Astro Islands: コンポーネントをアイランドとして分離し、React や Vue など複数のフレームワークを同じプロジェクト内で利用可能。
  • Zero JS, by default: ほとんどの JavaScript をビルド時に純粋な HTML に変換し、パフォーマンスを最適化。

詳細な説明については、Astro の公式ドキュメント をご覧ください。

Astro のセットアップ

Astro のセットアッププロセスはスムーズです。以下のステップに従って Astro ブログを開始しましょう。

1. プロジェクトの初期化

以下のコマンドを実行して新しい Astro プロジェクトを作成します。

npm create astro@latest

2. 設定プロンプト

セットアップ中、プロジェクトに関する選択を求められます。以下はその例です。

 astro   Launch sequence initiated.

   dir   Where should we create your new project?
         ./

  tmpl   How would you like to start your new project?
         Use blog template
 ██████  Template copying...

  deps   Install dependencies?
         Yes
 ██████  Installing dependencies with npm...

    ts   Do you plan to write TypeScript?
         Yes

   use   How strict should TypeScript be?
         Strict
 ██████  TypeScript customizing...

   git   Initialize a new git repository?
         Yes
 ██████  Git initializing...

  next   Liftoff confirmed. Explore your project!
         Run npm run dev to start the dev server. CTRL+C to stop.
         Add frameworks like react or tailwind using astro add.

         Stuck? Join us at https://astro.build/chat

╭─────╮  Houston:
│ ◠ ◡ ◠  Good luck out there, astronaut! 🚀
╰─────╯

3. 開発サーバーの起動

セットアップが完了したら、以下のコマンドを実行して開発サーバーを起動します。

npm run dev

デフォルトのサーバーは http://localhost:4321/ で利用可能です。

コンテンツコレクション

概要

Astro では、ブログ記事などのコンテンツを コレクション として管理します。詳しくは 公式ページのコンテンツコレクションに関するガイド をご覧ください。

src/content/ 配下に任意のディレクトリを作成し、その中に Markdown ファイルを配置します。 MDX もサポートされています。以下はブログ記事のファイル例です (blog/first-post.md)。

---
title: 'First post'
description: 'Lorem ipsum dolor sit amet'
pubDate: 'Jul 08 2022'
heroImage: '/blog-placeholder-3.jpg'
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
...

コレクションの定義

Astro では、Zod スキーマ検証ライブラリを使って src/content/config.ts にコレクションのメタデータ (フロントマター) と型を定義できます。この定義は任意ですが、スキーマ検証TypeScript タイピング の利点から推奨されます。

The src/content/config.ts file is optional. However, choosing not to define your collections will disable some of their best features, like frontmatter schema validation or automatic TypeScript typings.

以下は基本的な config.ts 設定の例です。

import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  // Type-check frontmatter using a schema
  schema: z.object({
    title: z.string(),
    description: z.string(),
    // Transform string to Date object
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
    heroImage: z.string().optional(),
  }),
});

export const collections = { blog };
キー必須
titlestringはい
descriptionstringはい
pubDateDateはい
updatedDateDateいいえ
heroImagestringいいえ

コレクションの定義に関する詳細は 公式ガイド をご参照ください。

コレクションの使用方法

Astro では、コンテンツコレクションにアクセスするために getCollectiongetEntry などの関数を提供しています。

たとえば、フロントマターは data オブジェクト内に格納されており、簡単にアクセスできます:

---
import { getEntry } from 'astro:content';

const blogPost = await getEntry('blog', 'welcome');
---

<h1>{blogPost.data.title}</h1>
<p>{blogPost.data.description}</p>

コレクションを効果的に定義・活用することで、コンテンツ管理を簡素化し、プロジェクト全体で一貫した構造を維持できます。

ページ

ルーティング

Astro は ファイルベースのルーティング を採用しており、pages ディレクトリ内のファイルは自動的に特定の URL へマッピングされます。以下にルーティングの例を示します:

ファイルURL
pages/index.astrohttps://<YOUR_DOMAIN>/
pages/about.astrohttps://<YOUR_DOMAIN>/about/
pages/blog/index.astrohttps://<YOUR_DOMAIN>/blog/

また、動的ルーティング もサポートされています。これは [...NAME] をディレクトリ名やファイル名として使用することで実現します。たとえば、新規プロジェクトで blog/[...slug].astro が動的ルーティング用に設定されています。

[...slug] は次の例のように getStaticPaths 関数内で処理されます:

---
import { type CollectionEntry, getCollection } 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.slug },
    props: post,
  }));
}
type Props = CollectionEntry<'blog'>;

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

<BlogPost {...post.data}>
  <Content />
</BlogPost>

ページ構造

Astro のページ、レイアウト、コンポーネントは、モダンなフロントエンド環境で馴染み深い構造に従います。コンポーネントをページ内に直接配置することもできますが、再利用可能な要素は components ディレクトリ内に保持することを推奨します。

以下は典型的なページ構造の例です:

src/
├── components/
│   ├── BaseHead.astro
│   ├── Header.astro
│   └── Footer.astro
├── layouts/
│   └── BlogPost.astro
├── pages/
│   ├── index.astro
│   ├── about.astro
│   └── blog/
│       ├── index.astro
│       └── [...slug].astro

Astro コンポーネント

Astro のコンポーネントは React の JSX/TSX に似た構文で記述されます。 React に精通している場合、Astro の構文への移行はスムーズに行えるはずです。以下は pages/index.astro ファイルのスニペットです:

---
import BaseHead from "../components/BaseHead.astro";
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
import { SITE_TITLE, SITE_DESCRIPTION } from "../consts";

// This will cause an error.
// const main = document.querySelector('main');
---

<!doctype html>
<html lang="en">
  <head>
    <BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
  </head>
  <body>
    <Header title={SITE_TITLE} />
    <main>
      <h1>🧑‍🚀 Hello, Astronaut!</h1>
      <!-- Additional content -->
    </main>
    <Footer />

    <script>
      // Use document, windoww, etc. here.
      const main = document.querySelector('main');
    </script>
  </body>
</html>

重要な考慮点

Astro のフロントマター(--- ブロック)は Node.js を使用してサーバー上で処理されます。 そのため、documentwindow といったブラウザ固有のオブジェクトはフロントマターでは利用できません。 これらを使用するとエラーが発生します:

 error   document is not defined
  Hint:
    Browser APIs are not available on the server.

    Move your code to a <script> tag outside of the frontmatter, so the code runs on the client.

    See https://docs.astro.build/en/guides/troubleshooting/#document-or-window-is-not-defined for more information.

ブラウザ関連の操作を行う場合は、上述の例のように <script> タグ内でラップして記述してください。

コンテンツのレンダリング

Astro では、CollectionEntry から抽出した Content コンポーネントを使用して、動的にコンテンツをレンダリングできます。以下の例は、pages/blog/[...slug].astro ファイル内で Content を使用する方法を示しています:

---
import { type CollectionEntry, getCollection } 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.slug },
		props: post,
	}));
}
type Props = CollectionEntry<'blog'>;

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

<BlogPost {...post.data}>
	<Content />
</BlogPost>

また、Markdown ファイルを直接インポートしてコンポーネントとして利用することも可能です。以下はその例です:

---
import { Content as PromoBanner } from '../components/promoBanner.md';
---

<h2>Today's promo</h2>
<PromoBanner />

Astro は静的および動的ルーティングを組み合わせた柔軟なアプローチを採用しており、直感的なレンダリングプロセスとコンポーネントシステムが特徴です。これにより、スケーラブルで高性能なウェブサイトを構築するための強力なツールとなっています。

ビルド

npm run build または astro build を実行することで、ビルドアーティファクトが dist/ ディレクトリに生成されます。これらのアーティファクトは完全にビルドされたサイトを表しており、デプロイの準備が整っています。以下は、セットアップ直後の生成出力例です:

ビルド後には、JavaScript は一切生成されません。これにより、ビルドは軽量かつ高効率になります。

ビルド出力の例

tree dist/ --dirsfirst

dist/
├── about
│   └── index.html
├── blog
│   ├── first-post
│   │   └── index.html
│   ├── markdown-style-guide
│   │   └── index.html
│   ├── second-post
│   │   └── index.html
│   ├── third-post
│   │   └── index.html
│   ├── using-mdx
│   │   └── index.html
│   └── index.html
├── fonts
│   ├── atkinson-bold.woff
│   └── atkinson-regular.woff
├── blog-placeholder-1.jpg
├── blog-placeholder-2.jpg
├── blog-placeholder-3.jpg
├── blog-placeholder-4.jpg
├── blog-placeholder-5.jpg
├── blog-placeholder-about.jpg
├── favicon.svg
├── index.html
├── rss.xml
├── sitemap-0.xml
└── sitemap-index.xml

重要なポイント

  • HTML 出力: すべてのページが静的な HTML ファイルとして事前にレンダリングされます。
  • JavaScript 非生成: Astro は、フレームワークやコンポーネントを通じて明示的に追加されない限り、JavaScript を生成しません。
  • 静的アセット: フォントや画像などの静的リソースはそのまま含まれ、不必要な処理が防止されます。

Astro のビルドプロセスは、スピード効率性 を重視して設計されており、パフォーマンスを最優先とするウェブサイトに最適です。

その他のトピック

Image コンポーネント

Astro は、最適化された画像処理のための Image コンポーネントを提供します。src/ ディレクトリに配置された画像は、ビルドプロセス中に変換され、WebP フォーマットに最適化されます。これにより、パフォーマンスが向上します。

推奨事項

  • 画像の最適化が必要な場合は、src/ ディレクトリに配置します。
  • 変換が必要なローカル画像は public/ ディレクトリを使用せず、src/ ディレクトリに配置してください。

詳細については、Astro Images Guide をご参照ください。

Tailwind CSS の統合

Astro は Tailwind CSS を統合システムを通じてサポートしています。 Tailwind をインストールするには、以下を実行してください:

npx astro add tailwind

このプロセスでは以下を行います:

  1. @astrojs/tailwind と必要な tailwindcss パッケージをインストールします。
  2. 最小限の設定を持つ tailwind.config.mjs ファイルを生成します。
  3. astro.config.mjs ファイルの integrations 配列に Tailwind を追加します。

Tailwind の使用例

<body>
  <Header />
  <main class="ml-2">
    <!-- コンテンツをここに追加 -->
  </main>
  <Footer />
</body>

詳細については、Tailwind Integration Guide をご覧ください。

IDE サポート

Astro は、開発体験を向上させるために IDE プラグインを提供しています。

IDE提供元安定性
VS CodeAstro安定版
JetBrainsJetBrains2023年11月時点で不安定な印象

これらのプラグインを活用することで、構文ハイライト、IntelliSense、自動補完、エラー検出が可能になります。

まとめ

Astro は、パフォーマンスシンプルさ開発者向けツールを重視することで、静的ウェブサイト構築の体験を楽しく効率的なものにしています。Astro Islands や Zero JS by default などの機能により、モダンな静的サイトジェネレーターとして高い注目を集めています。

この記事が、次回のプロジェクトで Astro を試してみるきっかけになれば幸いです。

Happy Coding! 🚀

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023