コード分割
JavaScript バンドルを複数のチャンクに分割し、必要な部分だけを読み込む最適化手法
パフォーマンスフロントエンド
コード分割とは
コード分割 (Code Splitting) は、JavaScript バンドルをルートごと、コンポーネントごとに複数のチャンクに分割し、初期ロード時に必要なコードだけを読み込む最適化手法である。SPA の初期バンドルサイズを削減し、LCP (Largest Contentful Paint) を改善する。
なぜ必要か
コード分割なし:
bundle.js (2MB) ← 全ページのコードを含む
初期ロード: 2MB ダウンロード → パース → 実行
コード分割あり:
main.js (200KB) ← 共通コード + 現在のページ
about.chunk.js (50KB) ← /about ページ用 (遅延読み込み)
admin.chunk.js (300KB) ← /admin ページ用 (遅延読み込み)
初期ロード: 200KB のみ
React での実装
React.lazy + Suspense
import { lazy, Suspense } from 'react';
// 動的インポート: /admin にアクセスした時だけ読み込む
const AdminPage = lazy(() => import('./pages/AdminPage'));
const SettingsPage = lazy(() => import('./pages/SettingsPage'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/admin" element={<AdminPage />} />
<Route path="/settings" element={<SettingsPage />} />
</Routes>
</Suspense>
);
}
Next.js の自動コード分割
Next.js はページごとに自動的にコード分割する。pages/about.tsx は /about にアクセスした時だけ読み込まれる。next/dynamic で コンポーネントレベルの分割も可能。
import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('../components/HeavyChart'), {
loading: () => <p>Loading chart...</p>,
ssr: false, // サーバーサイドではレンダリングしない
});
分割の粒度
| 粒度 | 方法 | 効果 |
|---|---|---|
| ルートレベル | ページごとに分割 | 最も効果的、必須 |
| コンポーネントレベル | 重いコンポーネントを遅延読み込み | モーダル、チャート、エディタ |
| ライブラリレベル | 大きなライブラリを別チャンクに | moment.js, lodash |
Vite / webpack の設定
// vite.config.ts: マニュアルチャンク分割
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
charts: ['recharts'],
},
},
},
},
});
プリフェッチ
コード分割したチャンクを、ユーザーが遷移する前にバックグラウンドで先読みする。
<!-- ユーザーが /admin に遷移しそうな時に先読み -->
<link rel="prefetch" href="/admin.chunk.js">
Next.js の <Link> コンポーネントは、ビューポートに入ったリンク先のチャンクを自動的にプリフェッチする。
実務での活用方法は関連書籍にも詳しい。