PR

【Next.jsブログ構築】複数のMarkdown記事を読み込みトップページに新着一覧を表示する方法

Next.js のトップページに、読み込まれた Markdown 記事がリスト状に並んで表示されている様子を表現したイラスト。ファイルを追加するだけで自動更新されるシステムのワクワク感を表現したイメージ。 VPS・RentalServer
この記事は約9分で読めます。
記事内に広告が含まれています。
スポンサーリンク

これまでの Next.js ブログサイト構築シリーズをまとめたページは以下の通りです。

前回の記事では、WordPress から抽出した Markdown 記事を
Next.js のシステムで読み込み、
ブラウザに綺麗なデザインで表示させる基本手順を解説しました。

しかし、今の状態ではトップページに1つのテスト記事が固定で表示されているだけです。
本格的なブログとして運用するには、
複数の記事を自動で読み込んでリスト状に並べる
「新着記事の一覧表示」が必要になります。

この記事はシリーズの第6回です。
前回までに posts フォルダへ Markdown を置き、gray-matter
タイトルや日付を取り出して1記事を表示できるところまで進んでいる前提で、
手順を書いています。

ここからは、Next.js(App Router)のトップページで
posts 内の複数 Markdown をサーバー側でまとめて読み込み、
日付の新しい順(新着順)の一覧として並べるところまでを目指します。
取得処理は lib/posts.ts に分け、
レイアウトは page.tsx と Tailwind CSS で整えます。

トップページに新着記事が並ぶようになると、だんだんブログらしくなります。
自分で Web ページを作り上げていく楽しさを感じながら
今回も進めたいと思います。

テスト用の一覧記事を追加する

現在、記事データを保管している posts フォルダには、前回のテスト記事が1つだけ入っています。
一覧として並べる仕組みをテストするためには、日付の異なる複数のダミー記事が必要です。

今回からは、VPS への直接接続の設定を済ませた強力な AI エディタである Cursor を使って作業を進めていきます。

  1. Cursor の画面左側にあるファイル一覧から、 posts フォルダを右クリックします。
  2. 表示されたメニューから「新しいファイル…」を選択し、ファイル名を test-1.md と入力して Enter を押します。
  3. 開いた右側の画面に、以下の内容をコピー&ペーストして保存(Ctrl+S)します。
---
title: "テスト記事その1"
date: "2026-03-31"
---
これは1つ目の追加テスト記事です。一覧画面で正しく並ぶかどうかの確認に使います。
  1. 同じ手順で、今度は test-2.md というファイルを作成し、以下の内容を貼り付けて保存します。※並び替えをテストするため、日付を少し新しくしてあるのがポイントです。
---
title: "テスト記事その2:日付の確認"
date: "2026-04-01"
---
これは2つ目のテスト記事です。日付が新しいものが一番上(一番先)に表示されれば、並び替え機能は成功です。
Cursor のエクスプローラで posts フォルダの下にサンプルページが並んで表示された画像

テスト用の記事を作成すると、Cursor の画面左側のエクスプローラーに上の画像のように posts フォルダの中に Markdown ファイルが並びます。

これで、記事データの下準備が整いました。

記事データを一括取得する裏方プログラムの作成

次に、記事データを集めて整理するための仕組みを作ります。

トップページのプログラムに直接複雑な処理を書くと、コードが長くなりすぎて管理が難しくなります。そのため、データ処理だけを担当する「裏方のプログラムファイル」を新しく専用で作るのが、 Next.js の賢い設計ルールです。

  1. Cursor の画面左側のファイル一覧で、一番外側の余白部分を右クリックし、「新しいフォルダー」を選択します。フォルダ名を lib と入力して Enter を押します。
  2. 作成した lib フォルダを右クリックし、「新しいファイル…」を選択して、ファイル名を posts.ts と入力します。
  3. 開いた画面に、以下のプログラムをすべてコピー&ペーストして保存します。
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';

// postsフォルダの場所を指定
const postsDirectory = path.join(process.cwd(), 'posts');

export function getSortedPostsData() {
  // /posts フォルダ内の .md ファイルだけを取得(他のファイルが混ざっても安全)
  const fileNames = fs
    .readdirSync(postsDirectory)
    .filter((name) => name.endsWith('.md'));

  const allPostsData = fileNames.map((fileName) => {
    // ファイル名から '.md' を削除して、記事の固有IDにする
    const id = fileName.replace(/\.md$/, '');

    // マークダウンファイルを読み込む
    const fullPath = path.join(postsDirectory, fileName);
    const fileContents = fs.readFileSync(fullPath, 'utf8');

    // gray-matter を使って上部の設定情報(タイトル、日付など)を取り出す
    const matterResult = matter(fileContents);

    // React でエラーにならないよう、 Date オブジェクトを文字列(YYYY-MM-DD)に変換する
    let dateString = matterResult.data.date;
    if (dateString instanceof Date) {
      dateString = dateString.toISOString().slice(0, 10);
    } else {
      dateString = String(dateString);
    }

    // 取得したデータと id をセットにして返す
    return {
      id,
      title: matterResult.data.title as string,
      date: dateString,
    };
  });

  // 記事を日付で並べ替える(新しい日付が上に来るようにする)
  return allPostsData.sort((a, b) => {
    if (a.date < b.date) return 1;
    if (a.date > b.date) return -1;
    return 0;
  });
}

このプログラムは、「 posts フォルダ内の Markdown ファイルだけを対象に読み取り、タイトルと日付だけを抽出し、新しい順に並び替えたリストを作る」という重要な役割を持っています。

プログラムの中盤で日付のデータを変換しているのは、画面を作るための React という仕組みが、JavaScript の「Date(日付)オブジェクト」をそのまま画面に表示しようとするとエラーになってしまうためです。あらかじめ表示用の「文字列」に直しておくことで、トラブルを防いでいます。

fs でファイルを読む処理はサーバー側でのみ動きます。今回の app/page.tsx はデフォルトがサーバーコンポーネントなのでそのまま呼び出せますが、ファイル先頭に 'use client' を付けてクライアントコンポーネントにすると動かなくなる点に注意してください。

トップページを新着記事一覧に書き換える

裏方プログラムの準備が完了したので、トップページ(page.tsx)からそれを呼び出し、美しいカード型のデザインで一覧表示させます。

  1. Cursor の画面左側から app フォルダを開き、その中にある page.tsx を開きます。
  2. 前回書いたコードをすべて消去し、以下のプログラムにまるごと書き換えて保存します。
import { getSortedPostsData } from '../lib/posts';

export default function Home() {
  // 1. さきほど作った裏方プログラムを呼び出して、全記事のデータを取得する
  const allPostsData = getSortedPostsData();

  // 2. 取得したデータをリスト状(カード型)に並べて画面に表示する
  return (
    <main className="max-w-3xl mx-auto p-8">
      <h1 className="text-3xl font-bold mb-8">新着記事一覧</h1>
      
      <ul className="space-y-4">
        {/* allPostsData の中身を1つずつ取り出して繰り返し表示する */}
        {allPostsData.map(({ id, date, title }) => (
          <li key={id} className="p-4 border border-gray-700 rounded-lg shadow-sm bg-gray-800">
            <span className="text-gray-400 text-sm">{date}</span>
            <h2 className="text-xl font-semibold text-white mt-1">
              {title}
            </h2>
          </li>
        ))}
      </ul>
    </main>
  );
}
  1. Cursor のターミナルを開き、念のためブログのディレクトリに移動してから Next.js を起動します。
cd ~/next-blog
npm run dev

起動したら、ブラウザでサイトにアクセスしてみましょう。

Next.js で新着記事が日付の新しい順に一覧表示されたブラウザの画面

ブラウザでサイトにアクセスすると、上の画像のように 「新着記事一覧」 という大きな見出しの下に、テスト記事が 「日付の新しい順」 に並んで表示されます。

狙い通り「日付の新しい順(降順)」で綺麗なリストとして表示されました!
並び替えの機能もバッチリ成功です。
posts.md を1つ足して保存し、ブラウザを更新しただけで行が増えていく様子を見ると、「自分のブログがちゃんとシステムとして動いている」という感覚が一気に近づきます。

まとめ

今回は、Next.js の Markdown ブログにおいて、複数ファイルを自動で読み込み、トップページに新着記事一覧を表示する仕組みを構築しました。

Date オブジェクトの変換処理など、少しシステム的な要素も増えましたが、コードを正しく配置することでエラーなく実装することができました。

今後 posts フォルダに新しい Markdown ファイルを追加するだけで、このトップページは自動的に更新されていきます。ついに「動く Web システム」としてのブログの心臓部が完成しましたね。

次回は、この一覧に並んだタイトルをクリックした際、それぞれの記事専用のページへ飛んで表示されるようにする「動的ルーティング」という機能の設定に進みます。

コメント

タイトルとURLをコピーしました