概要
next/dynamic を使うと、コンポーネントを初期バンドルから分離して必要なタイミングで読み込める。
ssr: false で SSR をスキップでき、window オブジェクトを参照するライブラリや重いビジュアライゼーション系コンポーネントに有効。
インストール
# 追加インストールは不要
基本的な遅延読み込み
// src/app/dashboard/page.tsx
import dynamic from "next/dynamic";
// HeavyChart は初期バンドルに含まれず、必要時に読み込まれる
const HeavyChart = dynamic(() => import("@/components/HeavyChart"), {
loading: () => <p className="text-sm text-gray-400">グラフを読み込み中...</p>,
});
export default function DashboardPage() {
return (
<main className="p-6">
<h1 className="mb-4 text-lg font-bold">ダッシュボード</h1>
<HeavyChart />
</main>
);
}
SSR を無効化する(クライアント専用コンポーネント)
// src/app/editor/page.tsx
import dynamic from "next/dynamic";
// window / document を参照するコンポーネントは SSR をスキップする
const RichTextEditor = dynamic(() => import("@/components/RichTextEditor"), {
ssr: false,
loading: () => <div className="h-40 animate-pulse rounded bg-gray-100" />,
});
export default function EditorPage() {
return (
<main className="p-6">
<h1 className="mb-4 text-lg font-bold">エディタ</h1>
<RichTextEditor />
</main>
);
}
名前付きエクスポートの遅延読み込み
// src/components/HeavyChart.tsx(名前付きエクスポート)
export function HeavyChart() {
return <div>グラフ</div>;
}
// 使う側
const HeavyChart = dynamic(
() => import("@/components/HeavyChart").then((mod) => mod.HeavyChart),
{ loading: () => <p>読み込み中...</p> }
);
ポイント
dynamic()でラップするだけで自動的にコードスプリットされるssr: falseはwindow/documentを参照する外部ライブラリに必須loadingオプションに渡したコンポーネントが読み込み中に表示される(loading.tsxと役割は同じ)- 名前付きエクスポートは
.then((mod) => mod.ExportName)で取り出す - App Router では
React.lazy+Suspenseでも同様のことができるが、next/dynamicは Next.js との統合が深くオプションが豊富