Web制作の現場において、永遠のテーマとも言える**「CMS(コンテンツ管理システム)選定」**。 クライアントからは「使い慣れているWordPressがいい」と言われることが多いですが、エンジニアとしては「パフォーマンス、セキュリティ、そして開発体験(DX)を考えるとNext.jsなどのモダンスタックで組みたい」というのが本音ではないでしょうか。
「Headless WordPress」という折衷案もありますが、APIのレスポンス速度やプラグインの干渉に悩まされることも少なくありません。
そこで今回は、私たちが最近のプロジェクトで採用頻度を高めている**国産ヘッドレスCMS「microCMS」について、「なぜ選んだのか(技術選定)」から、「Next.js App Routerでのプレビュー機能実装(ハマりポイント)」**まで、現場のコードと共に徹底解説します。
1. 技術選定:なぜ「WordPress」ではなく「microCMS」なのか?
私たちが技術選定を行う際、以下の3つの軸でCMSを評価します。
- クライアントの更新体験(UI/UX)
- APIのパフォーマンスと柔軟性
- 保守・運用コスト
1.1 クライアントにとっての「使いやすさ」
海外製のContentfulやStrapiも優秀ですが、管理画面が英語であったり、多機能すぎて非エンジニアには直感的でない場合があります。その点、microCMSは完全日本語対応であり、UIが極めてシンプルです。「WordPressの投稿画面より迷わない」と、クライアントからの評判も上々です。
1.2 画像配信の最適化(Imgix連携)
エンジニアとして最も恩恵を感じるのが、画像配信CDN(Imgix)が標準で組み込まれている点です。APIから返ってくる画像URLにクエリパラメータを付与するだけで、リサイズ、フォーマット変換(WebP/AVIF)、圧縮が可能です。
TypeScript
// Next.js側での画像最適化の負担が激減します
const imageUrl = `${article.eyeCatch.url}?w=800&q=80&fm=webp`;
これを自前で実装しようとすると、AWS Lambda + CloudFrontなどを構築する必要があり、工数が跳ね上がります。
1.3 「Headless WordPress」との比較
WordPressをAPIとして使う(WP GraphQLなど)構成も試しましたが、以下の課題がありました。
- APIレスポンスが遅い: PHPが動くため、TTFB(Time To First Byte)が数百ミリ秒かかることがある。
- セキュリティリスク: 管理画面自体への攻撃リスクは残るため、WAFなどの対策が必須。
これに対し、SaaSであるmicroCMSはインフラ管理が不要で、APIも爆速です。これが決定打となりました。
2. 実装の壁:App Routerでの「プレビュー機能」
ヘッドレスCMS導入時の最大の懸念点は、**「公開前の記事をどうやって確認するか(プレビュー)」**です。 WordPressなら標準機能ですが、Next.jsでは自前で実装する必要があります。
特に Next.js 13以降の App Router (Draft Mode) は、Pages Router時代とは実装方法がガラリと変わっており、ドキュメント通りにやっても動かないハマりポイントがあります。
2.1 Route Handler の実装 (app/api/draft/route.ts)
まずは、microCMSの管理画面から「プレビューボタン」を押した際にアクセスされるAPIエンドポイントを作成します。
【ここにmicroCMS管理画面の「APIプレビュー設定」画面のスクショを貼る】
TypeScript
// app/api/draft/route.ts
import { draftMode } from 'next/headers';
import { redirect } from 'next/navigation';
import { getDetail } from '@/libs/microcms'; // microCMSクライアント
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get('secret');
const slug = searchParams.get('slug');
// 1. シークレットキーの検証(セキュリティ対策)
if (secret !== process.env.MICROCMS_DRAFT_SECRET || !slug) {
return new Response('Invalid token', { status: 401 });
}
// 2. 記事が存在するか確認(存在しないIDでのドラフトモード入りを防ぐ)
const post = await getDetail(slug, {
draftKey: searchParams.get('draftKey'), // microCMSから渡されるdraftKey
});
if (!post) {
return new Response('Invalid slug', { status: 401 });
}
// 3. Draft Modeを有効化(Cookieがセットされる)
draftMode().enable();
// 4. 実際の記事ページへリダイレクト
// 以前のres.setPreviewData({})とは異なり、これだけでOK
redirect(`/articles/${slug}`);
}
2.2 ページコンポーネントでの分岐処理
次に、記事詳細ページ側で「通常モード」か「ドラフトモード」かを判定し、取得するデータを切り替えます。
TypeScript
// app/articles/[slug]/page.tsx
import { draftMode } from 'next/headers';
import { getDetail } from '@/libs/microcms';
import { notFound } from 'next/navigation';
export default async function ArticlePage({ params }: { params: { slug: string } }) {
const { isEnabled } = draftMode();
// ドラフトモードが有効なら、キャッシュを無視して最新を取得
const data = await getDetail(params.slug, {
// isEnabledがtrueの時はdraftKeyが必要だが、
// ここでは単純化のため省略。実際はCookieやContextから取得する工夫が必要
draftKey: isEnabled ? '...retrieved_key...' : undefined
});
if (!data) {
notFound();
}
return (
<main>
{isEnabled && (
<div className="bg-yellow-200 p-2 text-center">
現在プレビューモードで閲覧中
<a href="/api/disable-draft" className="underline ml-2">解除する</a>
</div>
)}
<h1>{data.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.content }} />
</main>
);
}
3. 現場のハマりポイントと解決策
実装中に遭遇したエラーと、その解決策を共有します。
ハマり①:プレビュー時に画像が表示されない
microCMSのリッチエディタからアップロードした画像が表示されない現象が発生しました。 原因: next/image の domains 設定漏れです。 解決策: next.config.js に microCMS の画像ドメイン(images.microcms-assets.io)を追加します。App Routerでは設定方法が変わっているので注意です。
JavaScript
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.microcms-assets.io',
},
],
},
};
ハマり②:更新しても本番に反映されない(On-demand ISR)
microCMSで記事を更新しても、本番サイトが古いまま……。これはNext.jsの強力なキャッシュ(Data Cache)が効いているためです。 解決策: Webhookを使って、更新時のみキャッシュをパージ(破棄)するAPIを実装します。
revalidatePath ではなく、タグベースの revalidateTag を使うのがモダンな手法です。
TypeScript
// microCMSのデータ取得関数
export async function getDetail(slug: string) {
const res = await fetch(`https://.../${slug}`, {
next: { tags: ['articles'] }, // タグを付与
});
// ...
}
// app/api/revalidate/route.ts (Webhookのエンドポイント)
import { revalidateTag } from 'next/cache';
export async function POST(request: Request) {
// 署名検証ロジックをここに書く(必須)
revalidateTag('articles'); // 'articles'タグが付いたキャッシュを一括パージ
return Response.json({ revalidated: true });
}
【ここにWebhookが正常に動作し、200 OKを返しているログ画面のスクショを貼る】
4. クライアントへの説明責任:SLAとダウンタイム
技術選定において、リスク説明は避けて通れません。microCMSはSaaSであるため、ごく稀にAPIサーバーがダウンする可能性があります(SLAは99.9%以上ですが)。
私たちはクライアントに対し、以下のように説明しています。
「WordPressはサーバーが落ちれば管理画面もサイトも見られなくなりますが、Next.js + microCMS構成の場合、APIが落ちてもサイト自体(フロントエンド)はキャッシュにより表示され続けるように設計可能です。つまり、閲覧者への機会損失を最小限に抑えられます」
この「可用性の高さ」こそが、静的生成(SSG)やISRを採用する最大のメリットの一つです。
5. まとめ:CMSは「管理画面」ではなく「API」で選ぶ時代
「クライアントが使い慣れているからWordPress」という思考停止から一歩踏み出し、「プロジェクトの成功(表示速度、セキュリティ、将来的な拡張性)」のために最適なCMSを選ぶ。それが私たちエンジニアの職務です。
- 非エンジニアにも優しいUI(microCMS)を採用し、更新体験を担保する。
- Next.jsのDraft ModeとISRを正しく実装し、運用のストレスをなくす。
- Imgix連携などの「隠れた機能」を使い倒し、パフォーマンスを最大化する。
Studio Puffでは、こうした技術的なこだわりを持って、クライアントのビジネスを加速させるWebサイト構築を行っています。「Headless CMSに興味はあるけど、導入が不安」という方は、ぜひ一度ご相談ください。