1. プロジェクトの背景と戦略的意義
モダンなWebフロントエンド開発において、MDX(Markdown + JSX)は単なるドキュメント形式ではなく、**「コンテンツとUIの融合レイヤー」**として機能します。本ドキュメントでは、Next.js 16 App Router環境におけるMDXのパフォーマンスを最大化し、開発体験(DX)を妥協なく追求するためのアーキテクチャ基準を策定します。
我々の目標は、サイトを単に「情報を説明する場」から、リッチなReactコンポーネントを埋め込んだ「インタラクティブに体験させる場」へと転換することです。画像最適化によるCLS(Cumulative Layout Shift)の排除、サーバーサイドでの目次(TOC)生成、および高精度なシンタックスハイライトの実装により、Lighthouseスコアの劇的な向上(実証値でパフォーマンス7ポイント増)と、ビジネス目標に直結するユーザーエンゲージメントの強化を実現します。
2. MDXアーキテクチャの選定基準と基本構成
Next.js 16では、用途に応じて「ビルド時バンドル」と「ランタイム変換」の2つのアプローチを厳格に使い分けます。
2.1 ユースケース別選定基準
| 選定項目 | @next/mdx (Static) | next-mdx-remote-client (Dynamic) |
| 主な用途 | About、LP、固定の技術ドキュメント | ブログ、CMS連携、ファイルシステムからの動的読み込み |
| ファイル配置 | src/app/ 内に .mdx を直接配置 | content/ 等、ビルドパイプライン外のディレクトリ |
| 変換タイミング | ビルド時にJavaScriptモジュールとしてバンドル | Server Components (RSC) でのランタイム変換 |
| コンポーネント管理 | mdx-components.tsx (グローバル/ビルド時) | components プロパティ (実行時/個別指定) |
2.2 Next.js 16 における非同期パラメータの実装標準
Next.js 15/16以降、params および searchParams は Promise 化されています。SEOメタデータ生成とページレンダリングの両方で、正しい await 処理を強制します。
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
type Props = {
params: Promise<{ slug: string }>;
};
// メタデータ生成における非同期処理
export async function generateMetadata(props: Props): Promise<Metadata> {
const { slug } = await props.params;
// ...データフェッチ
return { title: `Post: ${slug}` };
}
// ページコンポーネントにおける非同期処理
export default async function Page(props: Props) {
const { slug } = await props.params;
// ...MDX読み込みロジック
}
重要な注意: @next/mdx を使用する場合はプロジェクトルートに mdx-components.tsx が必須ですが、next-mdx-remote-client を使用する場合は、このファイルは適用されません。MDXRemoteコンポーネントの components prop に直接カスタムコンポーネントを渡す必要があります。
3. 正規表現を用いた画像最適化(next/image)実装要件
標準Markdownの「画像サイズ指定不可」に起因するレイアウトシフトを防止するため、URLハッシュを用いたサイズ注入フローを定義します。
3.1 埋め込みロジックと正規表現による抽出
ライターはMarkdown内で以下の形式でサイズを指定します。
- 記法:

レンダリングコンポーネント(Custom Image)では、以下のロジックで値を抽出します。
src文字列を#で分割し、後半部分を正規表現(\d+)_(\d+)でパース。- 抽出に成功した場合は
width,heightに割り当て。 - ハッシュが存在しない、またはパースに失敗した場合は、ビルドエラーを避けるためのフォールバック値(または
fillプロパティ)を適用する。
3.2 CLS防止とLighthouseへの影響
この手法により、ブラウザが画像を読み込む前に正確なアスペクト比で領域を確保できるため、CLSがゼロに抑制されます。これにより、Lighthouseのパフォーマンススコアが約7ポイント向上することが確認されています。
4. Shiki(Rehype Pretty Code)による高精度シンタックスハイライト
技術ドキュメントの品質を担保するため、VS Codeと同じ解析エンジンを使用する Shiki を標準採用します。
4.1 技術選定とパッケージ要件
サーバーサイドで完全な変換を行うことで、クライアントサイドのハイドレーションエラーを完全に回避します。
- 必須パッケージ:
rehype-pretty-code,@shikijs/transformers - 推奨設定:
theme: "plastic",keepBackground: true
4.2 高度な機能要件
@shikijs/transformers を導入し、以下のメタ情報レンダリングを実現します。
- 特定行のハイライト:
// [!code highlight]を含む行を視覚的に強調。 - Diff表示:
// [!code ++](緑)および// [!code --](赤)によるコード差分の明示。 - ファイル名表示:
title="filename.ts"メタ情報を検出し、figcaption要素としてレンダリング。
5. サーバーサイド目次(TOC)生成ロジック
クライアントサイドでのハイドレーション後のレンダリング(チラつき)を排除するため、サーバーサイドで完結するTOC生成プロセスを実装します。
5.1 パースプロセスとアンカーリンクの整合性
- 抽出:
extract-md-headingsを使用。このライブラリはソース文字列ではなく、**「ファイルの物理パス」**を引数に取る点に注意してください。 - 自動ID付与:
rehype-slugをプラグインとして統合し、本文中の各h2,h3にIDを自動付与します。 - 階層化UI: 抽出した
level(2 or 3) に基づき、TOCコンポーネント側で動的にパディング(pl-4等)を付与し、視覚的な階層構造を構築します。
6. Edge Runtimeの制約とキャッシュ戦略
グローバル配信を高速化する Edge Runtime の活用に際し、以下のアーキテクチャ上の制約を遵守してください。
6.1 Edge Runtime における実装上の制限
- Node.js API 非対応:
fsやpathは使用不可能です。ファイル読み込みはビルド時に完了させるか、Web標準APIのfetchを使用してください。 - ImageResponse の CSS 制限:
OG画像生成等に使用するImageResponseでは、CSSは Flexbox のサブセットのみをサポートします。 - スタイリングの知恵: 行数制限(Line Clamping)を実装する場合、通常のCSSではなく
-webkit-boxと-webkit-line-clampを用いたスタイリングが必要です。 - 日本語豆腐化対策: フォントの外部フェッチが必須です。
6.2 キャッシュと型安全性の担保
- 外部リソースキャッシュ: フォント読み込み時の
fetchにはcache: 'force-cache'を明示し、エッジでの不要な再フェッチを抑制します。 - 防衛的型パース:
gray-matterが返す Frontmatter はany型です。必ずparsePost等のラッパー関数を通し、data.tags ?? []のようなフォールバック処理を含む型安全なPost型へ変換してください。
7. 結論および実装上の留意点
本定義に基づいた実装は、単なるWebサイトを「高速なアプリケーション体験」へと昇華させます。EC、技術ポータル、コミュニティサイトにおいて、MDXはUIとコンテンツを疎結合かつ強力に結びつける中核技術となります。
最終チェックリスト
- Turbopack制約: 現在、TurbopackではJavaScript関数をプラグインに渡せません。
remark/rehypeプラグインを指定する際は、関数ではなく文字列名を使用する等の対応が必要になる場合があります。 - セキュリティ (RCE): リモートMDX(
next-mdx-remote-client)を使用する場合、信頼できないソースからのコンテンツ実行は厳禁です。MDXはサーバー上でJavaScriptとして実行されるため、リモートコード実行のリスクを常に意識してください。
推奨技術スタック
- Core:
@next/mdx,next-mdx-remote-client - Transformers:
remark-gfm,rehype-pretty-code,@shikijs/transformers,rehype-slug - Data Handling:
gray-matter,extract-md-headings - Styling:
@tailwindcss/typography(proseクラスの活用)