ブログコンテンツの移行:ContentfulからNext.jsの静的Markdownへ
August 12, 2025 開発ノート Next.js Contentful Markdown データ移行

ContentfulのようなヘッドレスCMSからNext.jsプロジェクトの静的Markdownファイルへブログコンテンツを移行することは、デプロイの簡素化や外部依存関係の削減といった利点をもたらします。この投稿では、Contentfulからデータを抽出し、静的Markdown形式に変換するプロセスを詳しく説明します。
Contentfulのデータ構造を理解する
移行の前に、Contentfulでブログデータがどのように構造化されているかを理解することが重要です。主要なフィールドには通常、以下が含まれます。
- タイトル: 投稿のタイトル。
- 公開日: 投稿が公開された日付。
- スラッグ: 投稿のURLフレンドリーな識別子。
- 説明/抜粋: 投稿の簡単な要約。
- タグ: 投稿に関連付けられたカテゴリまたはキーワード。
- コンテンツ: 投稿の本文。多くの場合、リッチテキスト形式です。
Contentfulからデータを取得する
Contentfulは、コンテンツを取得するためのContent Delivery APIを提供しています。Space IDとAccess Tokenが必要です。
GET https://cdn.contentful.com/spaces/{SPACE_ID}/environments/master/entries?access_token={ACCESS_TOKEN}&content_type=pageBlogPost&order=-fields.publishedDate&select=fields.title,fields.publishedDate,fields.slug,fields.shortDescription,fields.content,fields.tags
コンテンツに関する重要な注意点: Contentfulのリッチテキストフィールドは、プレーンなMarkdownやHTMLではなく、特定のJSON形式でコンテンツを返します。contentフィールドがプレーンテキストの場合、埋め込み画像や複雑な書式設定が含まれていない可能性があります。リッチテキストの場合、通常はHTMLやMarkdownに変換するためにライブラリ(例:@contentful/rich-text-html-renderer)が必要になります。私たちの場合、contentフィールドはプレーンテキストであったため、変換が簡素化されました。
Markdown形式への変換
各Contentfulエントリは、YAMLフロントマターを持つMarkdownファイルに変換する必要があります。
フロントマターの構造: フロントマターは、Markdownファイルの先頭にあるYAMLブロックで、メタデータを含みます。
title: "あなたの投稿タイトル"
date: "YYYY-MM-DD"
description: "あなたの投稿の簡単な説明。"
tags: ["タグ1", "タグ2"]
---
コンテンツ本文: 投稿の本文はフロントマターの後に続きます。Contentfulのコンテンツがすでにプレーンテキストであれば、そのまま使用できます。適切な改行が維持されていることを確認してください。
移行の自動化
Node.jsスクリプトでこのプロセスを自動化できます。
- Contentfulから関連するすべてのエントリを取得します。
- 各エントリを反復処理します。
- フロントマターのデータを抽出します。
- ファイル名には
slugを使用します。 - Markdownファイルの内容(フロントマター+本文)を構築します。
- 目的のディレクトリ(例:
src/app/blog/en/)にファイルを書き込みます。
スクリプトの例(概念):
const fs = require('fs');
const path = require('path');
// ... (Contentfulデータ配列) ...
posts.forEach(post => {
const frontMatter = `---
title: ${JSON.stringify(post.frontMatter.title)}
date: ${post.frontMatter.date}
description: ${JSON.stringify(post.frontMatter.description)}
tags: [${post.frontMatter.tags.map(tag => JSON.stringify(tag)).join(', ')}]
---
`;
const markdownContent = `${frontMatter}
${post.content}`;
const filePath = path.join(postsDirectory, post.lang, `${post.slug}.md`);
fs.writeFileSync(filePath, markdownContent, 'utf8');
});
画像の処理
Contentfulのリッチテキストフィールドに埋め込まれた画像は、テキストコンテンツの一部ではありません。それらは別のアセットです。
- 課題: APIを介して画像を直接取得し、Markdownに埋め込むには、リッチテキストJSONの解析、アセットURLの取得、画像のダウンロード、そしてMarkdownの更新が必要です。
- 実用的な解決策: よりシンプルなセットアップの場合、画像を手動でダウンロードして
public/imagesディレクトリに配置し、Markdownで相対パスを使用して参照できます(例:)。
これらの手順に従うことで、ブログコンテンツを動的なCMSから静的なファイルベースのシステムに正常に移行し、Next.jsのデプロイを簡素化できます。