⚛️

MDX の紹介と導入【Next.js】

に公開2

はじめに

先日、Next.js の勉強会で、MDX の実装について取り上げました 🫐

勉強会で作成したアプリのデモ

prompt-box

Markdown の書きやすさと、React コンポーネントの柔軟性を、
両方活かせる MDX は、筆者が個人的に好きな技術の1つでもあります!

今回は、MDX について調査したので、基礎的な内容をまとめました

時間の節約になれば、嬉しいです 🙌

MDX とは?

https://mdxjs.com/

MDX とは、Markdown の中で React コンポーネントを使えるようにした形式です

通常の Markdown では、テキストの装飾や構造化は可能ですが、
インタラクティブな要素や複雑な UI コンポーネントを埋め込むことは困難でした。

MDX を使うことで、以下のような利点があります:

  • Markdown の書きやすさを保ちながら、React コンポーネントが使える
  • 文章の中にインタラクティブなデモを埋め込める
  • 既存の React コンポーネントライブラリを活用できる
  • TypeScript との相性も良好

例えば、以下のように書くことができます:

src/app/sample/page.mdx

# 私のブログ記事

これは普通の **Markdown** のテキストです。

<MyComponent title="Hello World" />

そして、また Markdown に戻ります。

技術記事やドキュメント、ブログなどで、
表現力豊かなコンテンツを作成できるのが、MDX の最大の特徴です

Next.js で MDX を使う方法は?

Next.js で、MDX を使用する際の選択肢は、いくつかあります。

有力なのは、:

  1. @next/mdx: Next.js が公式にサポートする方法で、ローカルの MDX ファイルを直接ページとして使用できる
  2. next-mdx-remote-client: リモートの MDX コンテンツを効率的に処理できるライブラリ
  3. mdx-bundler: ビルド時に MDX をバンドルするためのライブラリ

今回の記事では、
より柔軟で実用的な next-mdx-remote-client を紹介していきます!

next-mdx-remote-client とは?

https://github.com/ipikuka/next-mdx-remote-client

next-mdx-remote-client は、Next.js アプリケーションでリモートの MDX コンテンツを読み込むためのライブラリです。

データベースや CMS、外部 API などから取得した MDX コンテンツを、
Next.js アプリケーション内で、安全にレンダリングすることができます!

📝 メモ:以前使われていた next-mdx-remote について

実は、以前まで next-mdx-remote というライブラリが広く使われていました。

しかし、next-mdx-remote は長い間メンテナンスされておらず、
MDX v3 への対応や App Router での安定性に課題がありました。

そこで登場したのが next-mdx-remote-client です!

next-mdx-remote-client の特徴

https://nextjs.org/docs/app/guides/mdx#remote-mdx

next-mdx-remote-client は、next-mdx-remote のフォークとして開発され、
Next.js の公式ドキュメントでも、推奨されているライブラリです!

主な特徴は、以下の通りです:

  • MDX v3 完全サポート
  • App Router と Pages Router 両方に対応
  • 内蔵エラーハンドリング機能
  • import/export 文のサポート
  • frontmatter の簡単な取得
  • 目次(TOC)作成の簡易化

Next.js への導入

https://nextjs.org/docs/app/guides/mdx#using-dynamic-imports

さて、基本的な概念を理解したところで、
Next.js への具体的な導入手順を確認してみましょう!

1. ライブラリのインストール

npm install next-mdx-remote-client

2. App Router での基本的な使用方法

// app/blog/[slug]/page.tsx
import { MDXRemote } from "next-mdx-remote-client/rsc";

// MDX コンテンツ(通常は外部ファイルから取得)
const mdxSource = `
# Hello MDX!

これは **MDX** で書かれたコンテンツです。

<CustomButton onClick={() => alert('クリック!')}>
  ボタンをクリック
</CustomButton>
`;

// カスタムコンポーネント
const CustomButton = ({ children, onClick }) => (
  <button
    onClick={onClick}
    className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
  >
    {children}
  </button>
);

export default function BlogPost() {
  return (
    <div className="prose mx-auto">
      <MDXRemote source={mdxSource} components={{ CustomButton }} />
    </div>
  );
}

3. ファイルから MDX を読み込む場合

// app/blog/[slug]/page.tsx
import { readFile } from "fs/promises";
import { join } from "path";
import { MDXRemote } from "next-mdx-remote-client/rsc";

export default async function BlogPost({ params }) {
  // ファイルシステムから MDX を読み込み
  const filePath = join(process.cwd(), "content", `${params.slug}.mdx`);
  const mdxSource = await readFile(filePath, "utf-8");

  return (
    <div className="prose mx-auto">
      <MDXRemote
        source={mdxSource}
        components={{
          // カスタムコンポーネントをここで定義
          h1: (props) => <h1 className="text-4xl font-bold mb-4" {...props} />,
          p: (props) => <p className="mb-4 leading-relaxed" {...props} />,
        }}
      />
    </div>
  );
}

4. frontmatter の活用

import { MDXRemote } from "next-mdx-remote-client/rsc";

export default async function BlogPost({ params }) {
  const mdxSource = `---
title: "MDX の使い方"
date: "2024-01-01"
author: "Developer"
---

# {frontmatter.title}

投稿日: {frontmatter.date}
著者: {frontmatter.author}

これは MDX のサンプルです。
`;

  return (
    <div className="prose mx-auto">
      <MDXRemote
        source={mdxSource}
        options={{
          parseFrontmatter: true,
        }}
      />
    </div>
  );
}

このシンプルなコードで、Markdown の書きやすさと React コンポーネントの柔軟性を
両方活かしたコンテンツが作成できます!

なぜ MDX なのか?

個人的には、MDX の魅力は、
コンテンツ作成の効率性と表現力の両立にあると、考えています!

MDX を選ぶ理由としては:

  • 書きやすさ: Markdown の直感的な記法を保持
  • 表現力: React コンポーネントで複雑な UI も表現可能
  • 再利用性: 既存のコンポーネントライブラリを活用できる
  • メンテナンス性: コンテンツとロジックを適切に分離
  • SEO 対応: 最近の SSR/SSG フレームワークとの相性が良い

Web 上に公開するページの大部分を、md 形式で作成しつつ、
ポイントでリッチな UI/UX を導入できるのが、便利です 👍

おわりに

最後まで読んでいただだき、ありがとうございます 🥳

ハンズオン形式で、
実際に手を動かして学習したい場合は、以下の教材もチェックしてみてください!!

https://zenn.dev/kazzyfrog/books/aiprompt-box

この記事が、少しでも参考になれば嬉しいです!
そして、もし、間違いや補足情報などがありましたら、ぜひコメントを追加してください!

Happy Hacking :)

参考

https://mdxjs.com/
https://nextjs.org/docs/app/building-your-application/configuring/mdx
https://github.com/ipikuka/next-mdx-remote-client

🫐 勉強会紹介:
https://b13o.com/services/handson-workshop

b13o Tech Blog

Discussion

ipikukaipikuka

As the creator of the next-mdx-remote-client package, I saw your article and really liked it — great work, you explained everything very well. I hope next-mdx-remote-client proves useful to many developers, and it makes me happy to know that.

kazzyfrogkazzyfrog

Wow, I am honored to get your comment 👋

I really like the next-mdx-remote-client.
It works very well to integrate MDX into the next.js project in a practical way.
Thanks for the best work.
Have a wonderful day ;)