Astro × microCMS × Vercelで構築するモダンブログの作り方 完全ガイド
はじめに
エンジニアになってから、個人ブログでさまざまな記事を書いてきましたが、そろそろリプレイスしたいと考え、Astroでシンプルなブログサイトを作成してみました。その作成手順について記事にしていきます。データ管理はmicroCMSを使用し、サイトのホスティングはVercelで構築しています。
作成したもの
作成した記事を一覧で表示するシンプルなデザインにしました。
Github
作成したサンプルデータは下記リポジトリに格納しています。
バージョン情報
今回使用したNodeと主なパッケージのバージョン情報です。
- Node.js - v18.14.2
- Astro - v2.3.0
- microcms-js-sdk - v2.3.3
技術概要
Astro
Astroは静的サイト生成ツールとして使用されるフレームワークです。
最大の特徴は、サーバーファーストであることです。JavaScriptを可能な限りサーバーで処理し、クライアントには静的なHTMLだけを送信しようとします。ビルド時にクライアントサイドのJavaScriptをできるだけ取り除くことで、サイトに表示するための必要なファイル量をできるだけ減らしています。そのため、ページの読み込みからユーザー操作時において高速にWebサイトを読み込むことが可能になります。
microCMS
microCMSはヘッドレスSMC(コンテンツ管理システム)のことで、ウェブサイトを表示するための情報の管理を行うことができるサービスです。
ヘッドレスについて
ヘッドレス(headless)は表示部分を持たないという意味で、単純にコンテンツのデータ管理に特化しています。ページ自体は開発者が実装し、APIスキームの定義やデータの構造などはヘッドレスCMSで作成して、APIを利用してそれらの内容を取得することができます。
一方で、WordPressやMovableTypeのような、データ入力画面の作成、データ管理、画面表示など全ての機能が揃ったシステムが存在しますが、この場合すべてがそのシステムの管理下に置かれます。全ての機能が揃っているため、要件とマッチしていれば工数の削減が可能ですが、案件によっては機能を満たしていないこともあます。そのような場合は、データ管理はヘッドレスCMSを利用し、実装部分を要件に合わせて開発していくことが可能になります。
Vercel
Vercelとは、Next.jsを開発したVercel Inc.が提供しているホスティングサービスです。gitリポジトリさえあれば、Vercelがコードを読み込み、設定なしで簡単にデプロイすることができます。
Astroのプロジェクト立ち上げ
まずは以下のコマンドラインを実行して、Astroを立ち上げます。
npm create astro@latest
プロジェクトのディレクトリに移動してnpm run devコマンドを実行すると、開発サーバーが立ち上がります。
cd astro-myBlog
npm run dev
> purple-proxima@0.0.1 dev
> astro dev
🚀 astro v2.3.0 started in 34ms
┃ Local http://127.0.0.1:3000/
┃ Network use --host to expose
http://127.0.0.1:3000/
にアクセスして以下の画面が表示されていればプロジェクトの立ち上げ成功です。
microCMSのセットアップ
astroの実装に入る前に、microCMSと連携して作成したブログデータを取得するためにmicroCMSのアカウントを作成します。
microCMSのアカウントを作成したら、今回利用するサービス名とサービスIDを任意のものに設定します。
API基本の情報を入力します。APIエンドポイントは実際にデータを取得、更新する際に必要になります。
APIスキーマの作成
APIから取得するスキーマを定義して、作成します。タイトル、メイン画像と記事の中身を格納するコンテンツを設定します。
コンテンツの追加
コンテンツを追加してブログを作成します。
コンテンツが表示されていれば成功です。
microCMS JavaScript SDKをインストール
microCMS JavaScript SDKをインストールします。
microCMS JavaScript SDKはmicroCMSのAPIを簡単に利用できるようにするためのJavaScriptライブラリです。ブラウザ環境とNode.js環境の両方で利用可能です。
以下のコマンドを実行して、AstroプロジェクトにmicroCMS JavaScript SDKをインストールします。
npm install microcms-js-sdk
SERVICE_DOMAIN='YOUR_DOMAIN' // microCMSのドメイン名
API_KEY='YOUR_API_KEY' // microCMSのAPI Key
ENDPOINT='YOUR_ENDPOINT' // microCMSのエンドポイント
microCMSのドメイン名とAPI Keyそれからエンドポイントを.envファイルに追加します。
import { createClient } from "microcms-js-sdk";
export const client = createClient({
serviceDomain: import.meta.env.SERVICE_DOMAIN,
apiKey: import.meta.env.API_KEY,
});
公式ドキュメントに従ってSDKをインポートし、microCMSクライアントを作成します。import.meta.envで.envファイルのドメイン名やAPI Keyにアクセスすることが可能です。これで、microCMSで作成したブログの中身の取得や更新ができるようになりました。
データ取得
import { microcmsClient } from "../api/microcms";
import type { MicroCMSQueries } from "microcms-js-sdk";
export const getAllBlogs = async (queries: MicroCMSQueries): Promise<any> => {
return await microcmsClient
.get({
endpoint: "myblog",
queries,
})
.then((res) => {
console.log(res);
return res;
})
.catch((err) => console.error(err));
};
microcmsRepositoryフォルダ内に、データを取得するメソッドを集約します。endpointはmicroCMSで設定したエンドポイントを記載し、queriesは取得件数の絞り込みやコンテンツの中で取得する要素を指定することができます。
{
contents: [
{
id: 'v5smscmimy',
title: '【Vue.js】リアクティブシステムの基礎',
createdAt: '2023-05-01T12:17:31.791Z',
url: [Object]
},
{
id: '5dbgueei73',
title: '配列やオブジェクト操作におけるTips',
createdAt: '2023-04-27T12:29:07.088Z',
url: [Object]
},
{
id: 'wn6apxr2ya79',
title: '初投稿',
createdAt: '2023-04-27T12:28:11.993Z',
url: [Object]
}
],
totalCount: 3,
offset: 0,
limit: 10
} <<< response all data
APIから正常にレスポンスされれば、コンソールに記事のタイトルや表示画像、作成された日時などの情報が表示されます。
export type BlogsData = {
contents: [
{
id: string;
title: string;
createdAt: string;
url: BlogUrl;
}
];
totalCount: number;
offset: number;
limit: number;
};
export type BlogUrl = {
url: string;
height: number;
width: number;
};
microcmsTypesに型情報を集約して、取得するデータを定義しておきます。
---
import Layout from "../layouts/Layout.astro";
import Card from "../components/Card.astro";
/** api */
import { getAllBlogs } from "../repositories/microcmsRepository";
const res = await getAllBlogs({ fields: ["id", "title", "createdAt", "url"] });
---
<Layout title="My Origin Blog">
<!-- header -->
<header class="header">
<div class="header-parent">
<div class="text-title">
<h1 class="text-gradient">My Blog</h1>
</div>
<div class="row">
<nav class="header__nav">
<ul>
<li class="current">
<a class="smoothscroll" href="">Home</a>
</li>
<li><a class="smoothscroll" href="">Profile</a></li>
<li><a class="smoothscroll" href="">About me</a></li>
<li><a class="smoothscroll" href="">Contact</a></li>
</ul>
</nav>
</div>
</div>
</header>
<main class="main">
<div class="content">
{
res.contents.map((content: any) => {
return (
<Card
href={content.id}
title={content.title}
url={content.url.url}
createdAt={content.createdAt}
/>
);
})
}
</div>
</main>
</Layout>
getAllBlogsのfieldsは取得したいデータ(ここではid、title、createdAt、url)を指定して、レスポンスデータをmap関数を使用して、コンテンツの中身をそれぞれViewに反映させることでTOP画面が完成します。
個別画面の実装
// Get list API detail data
export const getBlogsDetail = async (
contentId: string,
queries?: MicroCMSQueries
): Promise<BlogsDetail> => {
return await microcmsClient
.getListDetail({
endpoint: import.meta.env.ENDPOINT,
contentId,
queries,
})
.then((res) => {
console.log(res, "<<< response detail data");
return res;
})
.catch((err) => console.error(err));
};
次に記事をクリックした時の、個別記事の表示の実装を行います。
microcmsClientのgetListDetailメソッドを使用して、記事の詳細情報を取得するAPIを作成します。
export type BlogsDetail = {
id: string;
createdAt: string;
updatedAt: string;
publishedAt: string;
revisedAt: string;
title: string;
content: string;
};
取得するデータの型を定義します。
---
import Layout from "../layouts/Layout.astro";
/** types */
import type { BlogsDetail } from "../types/microcmsTypes";
/** api */
import {
getAllBlogs,
getBlogsDetail,
} from "../repositories/microcmsRepository";
/** utils */
import { formatDate } from "../utils/formatDate";
const { blogId } = Astro.params;
let blogData: BlogsDetail | null = null;
if (blogId) {
blogData = await getBlogsDetail(blogId);
}
---
<Layout title="blog">
<main>
<h1>{blogData ? blogData.title : ""}</h1>
<p>
投稿日:{
blogData ? new formatDate(blogData.revisedAt).toJpDateWithWeek() : ""
}
</p>
<div set:html={blogData ? blogData.content : ""} />
</main>
</Layout>
次にpages配下に[blogId].astroフォルダを作成します。ファイル名を[ブラケット]記法を用いて囲むことで動的ルーティングパラメーターを指定して、指定した条件に合致するルーティングを作成することができます。個々の記事をクリックすると、http://127.0.0.1:3000/レスポンスid
のようにルーティングされます。getBlogsDetailのfieldsは記事を識別するidを指定します。
getStaticPaths
このままだと個々の記事をクリックした場合、以下のエラーが表示され、記事本体の文章が表示されません。
Astroで動的ルーティングパラメーターを作成する場合は、getStaticPathsメソッドを使用する必要があります。
all routes must be determined at build time, a dynamic route must export a getStaticPaths() that returns an array of objects with a params property. Each of these objects will generate a corresponding route.
Astro Doc:https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
getStaticPathsメソッドは動的ルーティングを使用しているページで、ビルド時に静的生成が必要なパスを指定するために使用される関数です。
export async function getStaticPaths() {
const res = await getAllBlogs({ fields: ["id"] });
return res.contents.map((content) => {
return {
params: {
blogId: content.id,
},
};
});
}
[blogId].astroフォルダ内にgetAllBlogsメソッドで取得した、idをgetStaticPathsのparamsにあてることで、動的ルーティングの生成が可能となります。
日付の整形
export class formatDate {
_date: Date;
constructor(date: Date | string) {
if (date instanceof Date) this._date = date;
else if (typeof date === "string") this._date = new Date(date);
else this._date = new Date(date);
}
/**
* yyyy年mm月dd日に整形する
* @returns yyyy年mm月dd日
*/
toJpDateString = () => {
return `${this._date.getFullYear()}年${
this._date.getMonth() + 1
}月${this._date.getDate()}日`;
};
/**
* yyyy年mm月dd日(曜日)に整形する
* @returns yyyy年mm月dd日(曜日)
*/
toJpDateWithWeek = () => {
const week = ["日", "月", "火", "水", "木", "金", "土"];
const dayOfWeek = week[this._date.getDay()];
if (this._date === undefined || dayOfWeek === undefined) return "ー";
return `${this.toJpDateString()}(${dayOfWeek})`;
};
}
リクエストのcreatedAtパラーメータで記事の作成日時を表示させることができますが、そのまま表示させるとUTCやミリ秒まで表示される為、日付を整形するユーティリティを作成しておきます。
<span class="update-date"
>{new formatDate(createdAt).toJpDateWithWeek()}</span
>
個々のコンポーネントでクラスのインスタンスを生成することで、年月日(曜日)で表示されるようになります。
Vercel
最後にVercelにログインして、作成したWebサイトをホスティングを行います。
ログインが完了したら、公開しているGitHubのリポジトリとVercelを接続します。
接続したいGithubのリポジトリにVercelをインストールして、ビルドの設定を行います。
最後に、プロジェクト名・フレームワーク・環境変数などを設定して「Deploy」を押します。
「Congratulations!」と表示されていれば、デプロイ完了です。
さいごに
今回は、Astro×microCMS×Vercelでブログサイトを作成してみました。 どれも初めて触れる技術でしたが、1日で実装と構築を行うことができました。もし何か間違いがあれば、ご指摘いただけると助かります。
文献
Discussion
.envにENDPOINTの設定をする旨を追加していただくと、自分のような初学者の方にもわかりやすいと思います。
とても参考になりました。
コメントありがとうございます。
.envファイルを設定する旨、項目追加しておきます