TL;DR
エンジニアの方であれば、自分で管理画面を作ったり、VSCode とマークダウンで記事を作成するでしょうから CMS は不要かと思います。しかし、管理画面から記事を投稿したい人や、マークダウンを扱えないクライアントさんには、CMS を使う必要があります。
この記事では、Next.js 13~ と TypeScript による microCMS の 2023 年 6 月現在の導入方法について解説します。実際のコードを交えながら、microCMS の基本的な使い方から、より高度な実装方法までをカバーします。
開発環境 | バージョン |
---|---|
Next.js (Pages Router) | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
microCMS の基本
microCMS とは、ヘッドレス CMS(Content Management System)の一つです。ヘッドレス CMS とは、フロントエンドとバックエンドが完全に分離された CMS のことを指します。これにより、データの入力と表示が分離され、任意のフロントエンドでデータを表示することができます。
microCMS は API によるデータの取得が可能で、これにより JavaScript のフレームワークである Next.js からデータを取得し、ウェブサイト上に表示することが可能となります。
microCMS でブログを作成する
microCMS の管理画面に入ります。
- 管理画面の左 > コンテンツ(API)の「+」をクリック > 「カテゴリ API」を作成
- API 名 > 「ブログ」、エンドポイント名を「blog」と指定
- API スキーマ > フィールド ID > 「title」、表示名を「タイトル」
- API スキーマ > フィールド ID > 「content」、表示名を「内容」
- API スキーマ > フィールド ID > 「eyecatch」、表示名を「アイキャッチ」、種類を「画像」
そして、画面右上の API プレビューをクリックすると、情報が表示されますので、X-MICROCMS-API-KEY の右に書いてあるキーをコピーしておきます。
microCMS でカテゴリの作成
- 管理画面の左 > コンテンツ(API)の「+」をクリック > 「カテゴリ API」を作成
- API 名 > 「カテゴリ」、エンドポイント名を「 categories」と指定
- API スキーマ > フィールド ID > 「name」、表示名を「カテゴリ名」
- API スキーマ > フィールド ID > 「slug」、表示名を「スラッグ」
次にブログの API に再度移動して
- API スキーマのフィールド ID を「category」、表示名を「カテゴリ」、種類を「複数コンテンツ参照 - カテゴリ」
「複数コンテンツ参照」にすることで複数のカテゴリを設定できます。
これでブログとカテゴリの結びつきができました。
Next.js
Next.js をインストールします。プロジェクト名は、micro-cms とします。
npx create-next-app@latest micro-cms
microcms-js-sdk をインストールします。
npm install --save microcms-js-sdk
ルートに、lib/client.ts を作成し、次のように記述します。
import { createClient } from "microcms-js-sdk";
export const client = createClient({
serviceDomain: process.env.SERVICE_DOMAIN || "",
apiKey: process.env.API_KEY || "",
});
また、ルートに.env.development.local を作成し、先程コピーした microCMS の情報を書き込みます。API_KEY の横に、コピーしたキーを追加し、SERVICE_DOMAIN の横には、microCMS 管理画面の左上にあるドメインを追加します。
API_KEY=ここにX-MICROCMS-API-KEY の右に書いてあるキーを貼り付けます
SERVICE_DOMAIN=microCMSで発行されたドメイン名を貼り付けます
ビルドエラー 「check serviceDomain and apiKey」
ビルド時に以下のようなエラーがでることがあります。
info Collecting page data ...Error: parameter is required (check serviceDomain and apiKey)
at exports.createClient
.env.development.local
の設定は通常、開発時(next dev)にしか適用されません。ビルド(next build)をローカルで行っている場合、それらの環境変数が適用されない可能性があります。
対処法としては.env.local という名前の新しいファイルを作成し、.env.development.local の内容をそのままコピーします。これでビルド時にも環境変数が適用されて、ビルドエラーが解決します。
ブログ一覧ページ
pages/blog/index.tsx を作り、次のように編集します。
// src/pages/blog/index.tsx
import Link from "next/link";
import { client } from "lib/client";
type Category = {
id: string;
name: string;
};
type Blog = {
id: string;
title: string;
category: Category[];
};
const Blog = ({ blog }: { blog: Blog[] }) => {
return (
<div className="content">
{blog.map((blogItem) => (
<div key={blogItem.id}>
<ul>
<li>
{blogItem.category.map((categoryItem: Category) => (
<Link
key={categoryItem.id}
href={`/categories/${categoryItem.id}`}
>
{categoryItem.name}
</Link>
))}
</li>
</ul>
<h3 className="mb-10">
<Link href={`/blog/${blogItem.id}`}>{blogItem.title}</Link>
</h3>
</div>
))}
</div>
);
};
export default Blog;
export const getStaticProps = async () => {
const blogData = await client.get({ endpoint: "blog" });
return {
props: {
blog: blogData.contents,
},
};
};
Image コンポーネントを使用する
Next.js の next/image を使用して外部の画像を最適化するには、 next.config.js ファイルにその画像のホストを設定する必要があります。これは、不適切な画像のリンクや潜在的に危険な URL を防ぐためのセキュリティ対策です。next.config.js を以下のように編集してみてください。
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
images: {
domains: ["images.microcms-assets.io"],
},
};
詳細ページ
詳細ページを作ります。タイトル、カテゴリー、アイキャッチ画像、本文を表示します。次のコードは Next.js と microCMS を使ってブログ記事を表示するためのものです。
// src/pages/blog/[id].tsx
import { client } from "lib/client";
import Image from "next/image";
import Link from "next/link";
type Eyecatch = {
url: string;
height: number;
width: number;
};
type Category = {
id: string;
name: string;
};
type Blog = {
id: string;
title: string;
publishedAt: string;
content: string;
category: Category[];
eyecatch: Eyecatch;
};
export default function BlogId({ blog }: { blog: Blog }) {
const date = new Date(blog.publishedAt).toLocaleDateString();
return (
<main className="content">
{blog.eyecatch && (
<Image
src={blog.eyecatch.url}
alt="blog eyecatch"
width={blog.eyecatch.width}
height={blog.eyecatch.height}
/>
)}
<h1>{blog.title}</h1>
<p>{date}</p>
{blog.category &&
blog.category.map((categoryItem) => (
<p key={categoryItem.id}>
<Link href={`/categories/${categoryItem.id}`}>
{categoryItem.name}
</Link>
</p>
))}
{blog.content && (
<div
dangerouslySetInnerHTML={{
__html: `${blog.content}`,
}}
/>
)}
</main>
);
}
export const getStaticPaths = async () => {
const data = await client.get({ endpoint: "blog" });
const paths = data.contents.map((content: Blog) => `/blog/${content.id}`);
return { paths, fallback: false };
};
export const getStaticProps = async (context: { params: { id: string } }) => {
const id = context.params.id;
const data = await client.get({ endpoint: "blog", contentId: id });
//console.log(data) // ここで取得したデータをログ出力
return {
props: {
blog: data,
},
};
};
それでは、それぞれの部分について詳しく見ていきましょう。
モジュールのインポートと型定義
最初の部分では、必要なモジュールをインポートしています。また、取得したブログ記事のデータに対する型を定義しています。Blog
型は一つのブログ記事を表し、Eyecatch
型は記事のアイキャッチ画像に関する情報を表しています。
BlogId
コンポーネント
BlogId
は React の関数コンポーネントで、ブログ記事を表示するためのものです。props としてblog
を受け取り、記事のアイキャッチ画像、タイトル、日付、カテゴリー名、そして本文を表示します。本文は HTML 形式で取得されるため、dangerouslySetInnerHTML
属性を使っています。
getStaticPaths
関数
この関数は Next.js の静的生成(Static Generation)に必要なもので、生成すべきパスのリストを返します。ここではまずclient.get
を使って全てのブログ記事を取得し、その結果から各記事に対応するパス(/blog/<記事のID>
)を生成しています。
getStaticProps
関数
この関数も Next.js の静的生成に必要なもので、各パスに対する props(ここではblog
)を返します。ここでは引数のcontext
から記事の ID を取り出し、それを使ってclient.get
でその記事のデータを取得しています。
ドキュメント
以上、microCMS と Next.js を使ってブログを作成する方法を説明しました。詳しいサービスの使い方は、Next.js との連携| microCMS ドキュメントを参照してください。