噂のAstroに入門したので爆速でブログを作ってみる
dotD フロントエンドエンジニアの松村です。
弊社では普段、React や Next.js を使って開発することが多いのですが、
最近噂の Astro にやっと入門したので、紹介します。
Astroとは
Astro は、静的サイトジェネレータとして動作するフレームワークです。
以下のような特徴があります。
- アイランドアーキテクチャ:UI を独立したコンポーネントに分割できる Web アーキテクチャを採用してる。
- 自由な UI:React、Vue、Svelte、Solid などで作成されたコンポーネントをサポートしている。
- ゼロ JS:静的サイトとして生成することで、クライアントサイドの JavaScript を減らし、ページのスピードを向上させる。
- SSR も選択可能:静的サイトジェネレータとして構築されたが、サーバサイドレンダリングを併用できる。ページ毎にどちらを使用するか選択できる。
Astroできること・できないこと
LP やブログ、オウンドメディア、EC サイト、ポートフォリオなど、ユーザーにコンテンツを届けるいわゆる「Web サイト」を、高速で SEO に優れた形で構築できます。
一方で、ログインが必要なアプリケーションや、複雑な UI を持つ Web アプリケーションの構築には向いていません。
Astroをインストール
セットアップウィザードを開始するには下記のコマンドを叩きます。
# create a new project with yarn
yarn create astro
ウィザードの案内に従って設定を選択していきます。
プロジェクトを作成する場所を選択します。
今回は、コマンドを実行したディレクトリの配下にmy-blog
という名前で作ります。
astro Launch sequence initiated.
dir Where should we create your new project?
./my-blog
プロジェクトに最初からテンプレートを含めるかどうかを選択します。
空でも良いですが、今回はブログテンプレートで作ります。
tmpl How would you like to start your new project?
○ Include sample files
● Use blog template
○ Empty
TypeScript で書くかどうかを選択します。
ts Do you plan to write TypeScript?
● Yes ○ No
TypeScript の Strict モードにするかどうかを選択します。
use How strict should TypeScript be?
● Strict (recommended)
○ Strictest
○ Relaxed
依存関係をインストールするかどうかです。
特に理由がなければ Yes を選択します。
deps Install dependencies? (recommended)
● Yes ○ No
Git リポジトリの設定をするかどうかを選択します。
git Initialize a new git repository? (optional)
● Yes ○ No
以上を選択すると、セットアップが始まります。
✔ Project initialized!
■ Template copied
■ TypeScript customized
■ Dependencies installed
■ Git initialized
next Liftoff confirmed. Explore your project!
Enter your project directory using cd ./my-brog
Run yarn 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! 🚀
╰─────╯
✨ Done in 333.26s.
完了するとこんなファイル構成になります。
Next.js を使ったことがある方は、親近感のある構成だと思います。
たったこれだけでブログサイトの雛形が完成です。
記事コンテンツの管理
ブログの記事はcontent
ディレクトリに格納していくのですが、
Markdown ファイルで配置可能です。
(もちろん、HTML もサポートしています)
ですので、Web 技術に明るくない、運用担当者やライターでも簡単に記事を追加できます。
ページのルーティング
ページのルーティングは Next.js の pages router のように、
pages
ディレクトリのファイル単位で処理されます。
pages/index.astro
がルートコンテンツとして機能します。
pages/about.astro
は/about
のパスからアクセスできます。
また、動的なルーティングもサポートされています。
例えばpages/blog/[...slug].astro
というファイルを作成すると、
記事のスラッグに合わせて/blog/first-post
のようなパスでアクセスできます。
デザインの反映
全ページ共通のスタイルは、styles/global.css
に記述します。
ページやコンポーネント固有のスタイルは、各ファイルに<style>
タグの中に記述します。
小難しいことを考えなくても、生の HTML/CSS にかなり近い形で記述できます。
---
import HeaderLink from './HeaderLink.astro';
import { SITE_TITLE } from '../consts';
---
<header>
<nav>
<h2><a href="/">{SITE_TITLE}</a></h2>
<div class="internal-links">
<HeaderLink href="/">Home</HeaderLink>
<HeaderLink href="/blog">Blog</HeaderLink>
<HeaderLink href="/about">About</HeaderLink>
</div>
</nav>
</header>
<style>
header {
margin: 0;
padding: 0 1em;
background: white;
box-shadow: 0 2px 8px rgba(var(--black), 5%);
}
h2 {
margin: 0;
font-size: 1em;
}
h2 a,
h2 a.active {
text-decoration: none;
}
nav {
display: flex;
align-items: center;
justify-content: space-between;
}
nav a {
padding: 1em 0.5em;
color: var(--black);
border-bottom: 4px solid transparent;
text-decoration: none;
}
nav a.active {
text-decoration: none;
border-bottom-color: var(--accent);
}
</style>
レイアウト
レイアウトは、ページテンプレートのような再利用可能な UI 構造を作成するための Astro コンポーネントで、
ヘッダ、フッタ、ナビゲーションなどページ間で共通の UI を追加できます。
また、<slot />
によって、個々のページのコンテンツが挿入される位置を指定します。
Markdown で書かれた記事コンテンツに対しても、レイアウトを使って共通 UI を挿入したり、スタイルを当てることができます。
以下はレイアウトファイルのサンプルです。
---
import type { CollectionEntry } from 'astro:content';
import BaseHead from '../components/BaseHead.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import FormattedDate from '../components/FormattedDate.astro';
type Props = CollectionEntry<'blog'>['data'];
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
---
<html lang="en">
<head>
<BaseHead title={title} description={description} />
<style>
main {
width: calc(100% - 2em);
max-width: 100%;
margin: 0;
}
.hero-image {
width: 100%;
}
.title {
margin-bottom: 1em;
padding: 1em 0;
text-align: center;
line-height: 1;
}
</style>
</head>
<body>
<Header />
<main>
<article>
<div class="hero-image">
{heroImage && <img width={1020} height={510} src={heroImage} alt="" />}
</div>
<div class="prose">
<div class="title">
<div class="date">
<FormattedDate date={pubDate} />
{
updatedDate && (
<div class="last-updated-on">
Last updated on <FormattedDate date={updatedDate} />
</div>
)
}
</div>
<h1>{title}</h1>
<hr />
</div>
<slot /> <!-- ここにコンテンツが挿れられます -->
</div>
</article>
</main>
<Footer />
</body>
</html>
レイアウトファイルを使う側のサンプルです。
---
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>
getStaticPaths
関数でcontent/blog
配下の記事コンテンツを取得しています。
ヘッドレス CMS 等の API からコンテンツを取得することも可能です。
Build
yarn build
コマンドでビルドします。
ビルドが完了すると、dist
ディレクトリが作成され、その中に静的ファイルが生成されます。
よく見ると sitemap も自動で生成されていて、SEO を意識していることがわかります。
コンテンツを公開するには、このdist
ディレクトリ配下の全ファイルを、コンテンツ配信サーバにアップロードします。
SSR(サーバーサイドレンダリング)を使っていなければすべて静的ファイルですので、S3 などのストレージサービスに配置しても OK です。
感想
普段は React や Next.js を使うことが多いですが、それらと比べると
生の HTML/CSS 記述に近く、導入のハードルはかなり低いです。
Astro に React や Vue のコンポーネントを持ち込めるので、
React や Vue の初学者が入門編として触ってみるのも良いんじゃないでしょうか。
今回は、content
ディレクトリに直接ファイルを作成しましたが、
Headless CMS 等の API からコンテンツを取得することも可能です。
なので実務レベルでも、今後 EC サイトやオウンドメディアを立ち上げる機会があれば、積極的に使っていきたいと思います。
Discussion