こんにちは!4月から事業部が変わり、ビジネスアクセラレーション事業部の大瀧優杏です!🎀

今回はNext.js の学習を通じて、Markdown ファイルをデータソースにしたエンジニアブログアプリをローカルで作成しました 👏🏻
この記事では、学んだことをまとめましたので、ぜひ最後までご覧ください!

技術スタック

項目 内容
フレームワーク Next.js(Pages Router)
言語 JavaScript / JSX
スタイリング CSS Modules
Markdown パーサー gray-matter / remark / remark-html
Node.js バージョン v22.22.3(推奨)

ディレクトリ構成

nextjs-microblog/
├── components/
│   ├── Layout.js              # 共通レイアウト(ヘッダー含む)
│   └── layout.module.css
├── lib/
│   └── posts.js               # Markdownデータ取得ロジック
├── pages/
│   ├── _app.js
│   ├── _document.js
│   ├── index.js               # トップページ(記事一覧)
│   └── posts/
│       └── [id].js            # 記事詳細(動的ルート)
├── posts/                     # Markdownブログ記事
│   ├── ssg-ssr.md
│   ├── pre-rendering.md
│   ├── prerendering-about.md
│   └── react-next.md
├── public/
│   └── images/                # サムネイル画像
└── styles/
    ├── globals.css
    ├── Home.module.css
    └── utils.module.css

Next.js ってなに?

React のフレームワークで、プリレンダリングに対応しているのが大きな特徴です。

プリレンダリングって?

通常の React(Create React App など)は、ブラウザがページを開いたときに JavaScript をダウンロード → 実行 → HTML を組み立てる という流れで画面を表示します。
つまり JavaScript の処理が終わるまで、ユーザーには真っ白な画面が表示され続けます。

Next.js のプリレンダリングは、
あらかじめサーバー側で HTML を生成しておいて、ブラウザにはその完成済みの HTML を渡すという流れになります。

【通常の React】
ブラウザ → JS をダウンロード → JS を実行して HTML を組み立て → 画面表示

【Next.js(プリレンダリング)】
ブラウザ → 完成済みの HTML を受け取る → 画面表示 
         ↑ 最初からコンテンツが見える!

ユーザーが画面を開いた瞬間にコンテンツが表示されるので、体感の速さが全然違います
SEO 的にも、クローラーが HTML をそのまま読めるのでインデックスされやすいというメリットもあります!

レンダリング方式:SSG と SSR

Next.js には 2 つのレンダリング方式があって、ページごとに使い分けできます。

SSG(Static Site Generation)― 静的生成

ビルド時に 1 度だけ HTML を生成する方式。リクエストにすぐ返却できます。
公式でも推奨されていて、このブログもSSGで作りました。

適したページ:ブログ、ドキュメント、商品ページなど更新頻度が低いコンテンツ

SSR(Server-Side Rendering)― サーバーサイドレンダリング

ブラウザからリクエストごとに、サーバーが HTML を生成する方式。
常に最新データを返せますが、SSG よりはやや遅いです。

適したページ:SNS のユーザープロフィールなど更新が発生するコンテンツ

ルーティング

pages/ 配下のディレクトリ名・ファイル名が、そのまま URL になります。直感的でわかりやすいですね👏🏻

pages/
├── index.js          → /
└── posts/
    └── first-post.js → /posts/first-post

SSG でのデータ取得

ここがちょっと難しかったです。💦SSG で外部データ(Markdown など)を取得するには、専用の関数を使う必要があります。

getStaticProps

ビルド時に外部データを取得して、コンポーネントに props として渡す関数です。
SSG でしか使えないので注意!

export async function getStaticProps({ params }) {
  const postData = await getPostData(params.id);

  return {
    props: {
      postData,
    },
  };
}

getStaticPaths

動的ルート([id].js など)で SSG を使うときに必要になる関数です。
「どのパスに対してページを生成するか」を事前に設定します。

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

動的ルートでは getStaticPathsgetStaticProps必ずセットで書く必要があります。片方だけだとエラーになります。🚨

// pages/posts/[id].js

export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  const postData = await getPostData(params.id);
  return {
    props: {
      postData,
    },
  };
}

export default function Post({ postData }) {
  return (
    <div>
      <h1>{postData.title}</h1>
    </div>
  );
}

fallback オプションについて

fallback の値によって、paths に含まれていないURLにアクセスしたときの挙動が変わります。

動作
false paths 外のURLは 404 ページを返す
true paths 外のURLでも、サーバーサイドが動的にページを生成してくれる

今回は false にしたので、存在しない記事のURLにアクセスすると 404 になります。

Markdown → HTML 変換

gray-matter で frontmatter(タイトル・日付・サムネイル)を、remark + remark-html で本文を HTML に変換します。

// lib/posts.js
const matterResult = matter(filecontents);
const blogContent = await remark().use(remarkHtml).process(matterResult.content);

起動方法

bash
# 依存パッケージのインストール
npm install

# 開発サーバー起動
npm run dev
# → http://localhost:3000 でアクセス可能

完成したアプリケーション

トップページ(記事一覧)

記事詳細ページ

動作確認済み環境

  • OS: macOS
  • Node.js: v22.22.3
  • ブラウザ: Chrome / Safari

最後に

今回初めてNext.jsを扱いましたが、Reactベースのフレームワークということもあり、とっつきやすく感じました!
ローカル環境のみで完結してしまったのが少し心残りですが、時間ができればビルド&デプロイにも挑戦していきたいと思います!
記事の内容は以上になります!
最後までお読みいただきありがとうございました🙇🏻‍♀️