Next.js パフォーマンス
ルール
- 画像:常に
next/image を使用し、sizes を明示的に指定。priority はLCPヒーロー画像のみに設定。フォント:next/font を使用(レンダリングブロッキングを引き起こすGoogle <link> は使わない)。
- まず測定する:
@next/bundle-analyzer、next build の出力、Lighthouse。最も大きなチャンクから修正する。
- 重いクライアント専用ウィジェット(チャート、エディタ)には
dynamic(() => import(...), { ssr: false }) を使用。初期JSは可能な限り200KB gz未満に抑える。
- 積極的にキャッシュする:準動的ページには静的 +
revalidate(ISR)を使用。TTFBをブロックしないよう、loading.tsx/Suspenseを使って遅い部分をストリーミングする。
- ウォーターフォールを避ける:RSCで並列化し、繰り返しの
fetch はメモ化(リクエストごとに自動重複排除)、高コストな計算には unstable_cache を使用する。
パターン
import Image from 'next/image';
<Image src="/hero.jpg" alt="ダッシュボード" width={1200} height={630} priority sizes="100vw" />
<Image src="/avatar.png" alt="ユーザー" width={64} height={64} sizes="64px" />
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], display: 'swap' });
export default function RootLayout({ children }: { children: React.ReactNode }) {
return <html lang="ja" className={inter.className}><body>{children}</body></html>;
}
import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('@/components/chart'), { ssr: false, loading: () => <p>チャート読み込み中…</p> });
export const revalidate = 60;
const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true' });
module.exports = withBundleAnalyzer({});
チェックリスト