モダンなフロントエンド開発に!Next.jsの概要と導入方法
はじめに:モダンフロントエンド開発の進化と課題
ウェブアプリケーション開発は、ここ数年で劇的に進化しました。特にフロントエンド開発においては、React、Vue、Angularといったライブラリやフレームワークの登場により、リッチでインタラクティブなユーザーインターフェースを構築することが容易になりました。Single Page Application(SPA)の台頭は、従来のサーバーサイドでページ全体をレンダリングするMulti Page Application(MPA)とは一線を画し、よりネイティブアプリに近いスムーズな体験をユーザーに提供できるようになりました。
しかし、SPAにはいくつかの課題も存在します。
- SEO(検索エンジン最適化)の問題: SPAは初期ロード時に最小限のHTMLを読み込み、その後のページのコンテンツはJavaScriptによって動的に生成されます。多くの検索エンジンクローラーはJavaScriptを実行できますが、完全に実行できない場合や、レンダリングに時間がかかり、正しくコンテンツを認識できない場合があります。これは、SEOにとって不利に働く可能性があります。
- 初期表示速度の遅延: SPAはすべてのJavaScript、CSS、その他のアセットを初期ロード時にダウンロードして実行する必要があるため、特にネットワーク環境が悪い場合やデバイスの処理能力が低い場合、最初のコンテンツが表示されるまでに時間がかかることがあります(First Contentful Paint – FCPやLargest Contentful Paint – LCPといった指標に悪影響)。
- JavaScriptの実行依存: クライアントサイドでJavaScriptが実行されない環境(例えば、一部の古いブラウザやボット)では、コンテンツがまったく表示されない可能性があります。
- 開発・保守の複雑さ: プロジェクトが大規模になるにつれて、コード分割、ルーティング、状態管理、API連携などの設定が複雑になりがちです。
これらの課題を解決するために登場したのが、サーバーサイドレンダリング(SSR)や静的サイト生成(SSG)といった技術を統合したReactフレームワークです。その中でも、最も広く利用され、モダンなフロントエンド開発のデファクトスタンダードの一つとなっているのが Next.js です。
この記事では、Next.jsがどのようにこれらの課題を解決し、開発者とユーザー双方にメリットをもたらすのか、その概要から導入方法、主要機能、そして最新の推奨アーキテクチャであるApp Routerについて、詳細かつ網羅的に解説します。この記事を読み終える頃には、Next.jsを使ったモダンなウェブアプリケーション開発を始めるための土台がしっかりと築かれているはずです。
Next.jsとは? 概要と特徴
Next.jsは、Reactアプリケーションを構築するためのオープンソースのフレームワークです。Meta(旧Facebook)によって開発されたUIライブラリであるReactを基盤としていますが、React単体では提供されない多くの機能(ルーティング、データフェッチング戦略、APIルート、コード分割など)を統合し、開発者がより効率的に、かつ高いパフォーマンスとSEOを持つアプリケーションを構築できるように設計されています。
端的に言えば、Next.jsは「プロダクションレディなReactアプリケーションを素早く構築するためのフルスタックフレームワーク」です。
Next.jsの主な特徴を以下に挙げます。
- ゼロコンフィグレーション: 多くの設定が不要で、プロジェクトを作成してすぐに開発を開始できます。WebpackやBabelといった複雑なビルドツール設定に時間を費やす必要がありません。
- ファイルシステムルーティング: プロジェクトのディレクトリ構造に基づいて自動的にルーティングが生成されます。特定のディレクトリ(
app
またはpages
)にファイルを作成するだけで、それがそのままURLパスになります。 - ハイブリッドレンダリング: アプリケーションのページごとに、最適なレンダリング戦略を選択できます。
- Server-Side Rendering (SSR): リクエストごとにサーバーサイドでページをレンダリングします。動的なコンテンツやリアルタイム性の高い情報に適しています。
- Static Site Generation (SSG): ビルド時に静的なHTMLファイルを生成します。コンテンツが頻繁に更新されないブログ記事やランディングページなどに最適で、CDNから高速に配信できます。
- Incremental Static Regeneration (ISR): ビルド後も、指定した間隔やトリガーに基づいて静的なページをバックグラウンドで再生成します。SSGのパフォーマンスメリットを保ちつつ、コンテンツの更新に対応できます。
- Client-Side Rendering (CSR): 従来のReact SPAのように、クライアントサイドのJavaScriptでコンテンツをレンダリングします。ユーザー操作によって動的にコンテンツが変化する部分や、認証が必要なページなどに利用されます。
- API Routes: Next.jsアプリケーション内でAPIエンドポイントを簡単に作成できます。これにより、バックエンドを別途用意することなく、サーバーサイドのロジックやデータベースとの連携をNext.jsプロジェクト内で完結させることができます。
- Fast Refresh: 開発中にコードを変更すると、アプリケーションの状態を維持したまま、変更内容がほぼ瞬時にブラウザに反映されます。開発効率が大幅に向上します。
- TypeScriptサポート: TypeScriptが標準でサポートされており、型安全な開発が容易です。
- 組み込みの最適化:
- Automatic Code Splitting: 各ページが必要なJavaScriptコードのみを読み込むように自動的に分割されます。これにより、初期ロードのパフォーマンスが向上します。
- Image Optimization (
next/image
): 画像の遅延ロード、サイズ最適化、WebPなどのモダンフォーマットへの変換などを自動で行い、画像の表示パフォーマンスを向上させます。 - Font Optimization (
next/font
): Webフォントを自動で最適化し、レイアウトシフト(Cumulative Layout Shift – CLS)を防ぎます。 - Script Optimization (
next/script
): 外部スクリプトの読み込み戦略を制御し、パフォーマンスへの影響を最小限に抑えます。
- 豊富なスタイリングオプション: CSS Modules, Styled JSX (built-in), CSS-in-JSライブラリ (Styled Components, Emotionなど), Tailwind CSSなど、様々なスタイリング手法をサポートしています。
- Middleware: リクエストが処理される前にコードを実行できます。認証チェックやリダイレクトなどの用途に利用できます。
- Vercelとの高い親和性: Next.jsはVercelによって開発されており、Vercelへのデプロイが非常にスムーズです。Next.jsの機能(ISR, Middleware, Image Optimizationなど)を最大限に活かせるように最適化されています。
これらの特徴により、Next.jsは単なるReactのラッパーではなく、モダンなウェブアプリケーション開発における包括的なソリューションとして位置づけられています。
なぜNext.jsを選ぶのか? メリットの深掘り
Next.jsが多くの開発者や企業に選ばれているのには明確な理由があります。前述の特徴がもたらす具体的なメリットをさらに詳しく見ていきましょう。
1. SEOの劇的な向上
SPAのSEO課題は、Next.jsのSSRやSSGといったレンダリング戦略によって根本的に解決されます。
- SSR (Server-Side Rendering): ユーザーやクローラーからのリクエストがあった際に、サーバー側でReactコンポーネントをHTMLとしてレンダリングし、クライアントに返します。これにより、クローラーは完全にレンダリングされたHTMLコンテンツをすぐに取得でき、コンテンツの内容を正確に把握できます。動的なコンテンツが多いページや、ユーザー認証によって表示内容が変わるページに適しています。
- SSG (Static Site Generation): ビルド時にすべてのページを静的なHTMLファイルとして生成します。これらのHTMLファイルはCDNにキャッシュされることが多く、ユーザーからのリクエストに対してサーバーサイドでの処理を待つことなく、CDNから直接高速に配信されます。これにより、クローラーは非常に高速かつ確実にコンテンツを取得できます。コンテンツが頻繁に更新されないブログ記事、ドキュメント、マーケティングサイトなどに最適です。
- ISR (Incremental Static Regeneration): SSGのメリット(高速な配信)を享受しつつ、コンテンツの更新にも対応できます。ビルド後、指定した間隔(例: 60秒ごと)でバックグラウンドでページを再生成します。最初のアクセスでは古いキャッシュが表示されるかもしれませんが、次のアクセスからは新しいコンテンツが表示されるようになります。頻繁ではないが定期的に更新されるニュースサイトや商品一覧ページなどに有効です。
これらのレンダリング戦略を組み合わせることで、アプリケーションの各ページに最適なSEO対策を施すことが可能です。
2. パフォーマンスの最適化と高速なユーザー体験
ユーザーは高速なウェブサイトを好みます。ページのロードが遅いと、離脱率の増加やコンバージョン率の低下につながります。Next.jsは様々な組み込み機能により、アプリケーションのパフォーマンスを自動的に最適化します。
- Automatic Code Splitting: Next.jsは各ページを独立したJavaScriptバンドルに分割します。これにより、ユーザーが特定のページにアクセスした際に、そのページを表示するために必要なコードだけがダウンロードされます。アプリケーション全体のコードを一度にダウンロードする必要がないため、初期ロード時間が大幅に短縮されます。
- Prefetching:
next/link
コンポーネントは、ビューポート内に入ったリンク先のページのコードをバックグラウンドでプリフェッチします。これにより、ユーザーがリンクをクリックした際に、遷移先のページがほぼ瞬時に表示されるようになります。 - Image Optimization (
next/image
): 画像はウェブサイトのパフォーマンスに大きな影響を与える要素の一つです。next/image
コンポーネントは、画像のサイズをデバイスやビューポートに合わせて最適化し、WebPのようなモダンなフォーマットに変換します。また、画像の遅延ロード(Lazy Loading)を自動で行うため、ビューポート外の画像は必要になるまで読み込まれません。 - Font Optimization (
next/font
): Webフォントの読み込みは、ページの表示中にレイアウトがガタつく(CLS)原因となることがあります。next/font
はフォントファイルを自己ホスティングし、ロード中のレイアウトシフトを防ぐための措置を自動で行います。 - Script Optimization (
next/script
): Google Analyticsのような外部スクリプトは、ページのレンダリングをブロックし、パフォーマンスを低下させる可能性があります。next/script
コンポーネントを使用すると、スクリプトの読み込み戦略(beforeInteractive
,afterInteractive
,lazyonload
)を制御し、ページへの影響を最小限に抑えることができます。
これらの自動最適化機能により、開発者はパフォーマンスチューニングに多くの時間を費やすことなく、高速でスムーズなユーザー体験を提供できます。
3. 開発体験の劇的な向上
開発効率は、プロジェクトの成功に不可欠です。Next.jsは開発者がより快適にコードを書けるような機能を提供します。
- ゼロコンフィグレーション: 新しいプロジェクトを始める際に、WebpackやBabelなどの複雑な設定ファイルをいじる必要がありません。
create-next-app
コマンド一つで、開発に必要な環境が整います。 - Fast Refresh: コードを変更した際に、アプリケーション全体をリロードすることなく、変更箇所のみを更新し、コンポーネントの状態を維持します。これにより、UIの変更をリアルタイムに確認しながら開発を進められます。
- ファイルシステムルーティング: ディレクトリ構造がそのままURLになるため、ルーティング設定ファイルを作成したり管理したりする手間が省けます。直感的で分かりやすいルーティングシステムです。
- API Routes: フロントエンドとバックエンドを同じNext.jsプロジェクト内で開発できます。これにより、開発中の連携がスムーズになり、デプロイも一括で行えます。マイクロサービスアーキテクチャの一部としても利用可能です。
- TypeScriptの標準サポート: 設定ファイル(
tsconfig.json
)を作成するだけで、TypeScriptを使った型安全な開発がすぐに始められます。エディタの補完機能やエラーチェックを活用することで、バグを早期に発見し、開発効率とコードの品質を高められます。 - Middleware: 認証や国際化対応など、アプリケーション全体にかかる共通の処理を、ルーティング層で一元的に管理できます。
4. スケーラビリティと保守性
プロジェクトが成長するにつれて、コードベースの管理や機能拡張が重要になります。
- ファイルシステムルーティング: アプリケーションの構造がディレクトリ構造に反映されるため、ページの追加や削除、ネストされたルーティングなどが直感的に行えます。これにより、コードベースの見通しが良くなり、大人数での開発や長期的な保守が容易になります。
- API Routes: バックエンドロジックをAPI Routesとして分離することで、フロントエンドのコンポーネントとサーバーサイドの処理を明確に分けることができます。これにより、コードの責務が明確になり、保守性が向上します。また、小規模なバックエンド機能であれば、独立したサーバーを立てる必要がなくなり、アーキテクチャをシンプルに保てます。
- ハイブリッドレンダリング: アプリケーションの要件に応じて最適なレンダリング戦略を選択できるため、パフォーマンスと開発効率のバランスを取りながら、アプリケーションを効率的にスケールさせることができます。
5. 充実したエコシステムとコミュニティ
Next.jsは非常に人気が高く、活発なコミュニティがあります。
- Vercel: Next.jsの開発元であるVercelは、Next.jsアプリケーションのホスティングに特化したプラットフォームを提供しています。GitHub/GitLab/Bitbucketとの連携、自動デプロイ、ISRのサポート、Edge Functions、サーバーレス機能など、Next.jsの機能を最大限に引き出すための環境が整っています。
- 豊富なライブラリ: Reactのエコシステムをそのまま利用できるため、状態管理ライブラリ(Recoil, Zustand, TanStack Queryなど)、UIライブラリ(MUI, Ant Designなど)、テストライブラリ(Jest, React Testing Libraryなど)など、様々なライブラリと組み合わせて利用できます。
- ドキュメントと情報源: 公式ドキュメントは非常に充実しており、多くのチュートリアルやサンプルコードが公開されています。また、コミュニティによるブログ記事、書籍、動画なども豊富に存在するため、学習リソースに困ることはありません。
これらのメリットにより、Next.jsは個人プロジェクトから大規模なエンタープライズアプリケーションまで、幅広い用途で選択されています。
Next.jsのデメリット
Next.jsは多くのメリットを提供しますが、いくつかのデメリットも理解しておく必要があります。
- 学習コスト: Reactの基本的な知識に加えて、Next.js独自の概念(ファイルシステムルーティング、データフェッチング戦略、Server Components/Client Componentsなど)を学ぶ必要があります。特に、SSR, SSG, ISRといったサーバーサイドでのレンダリングや、App RouterにおけるServer ComponentsとClient Componentsの使い分けは、SPA開発とは異なる考え方が必要になるため、慣れるまでに時間がかかる場合があります。
- フレームワークの制約: Next.jsは多くの機能を提供するために、特定のディレクトリ構造や規約(Convention over Configuration)を採用しています。これにより開発が効率化される反面、React単体で開発するよりも自由度が低いと感じる場合があるかもしれません。特定のカスタマイズを行う際に、フレームワークの内部構造を理解する必要が生じることもあります。
- 特定のホスティング環境への依存(限定的): Next.jsはVercelで最大限のパフォーマンスと機能を発揮するように最適化されています。もちろん、他のプラットフォーム(Netlify, AWS Amplify, Azure Static Web Apps, Dockerコンテナなど)でもホスト可能ですが、ISRやEdge Functionsなどの一部の機能は、Vercel以外の環境では追加の設定や工夫が必要になる場合があります。
- バンドルサイズの増加の可能性: 多機能であるため、アプリケーション全体として見ると、React単体で最適化を細かく行った場合と比較して、初期バンドルサイズが大きくなる可能性があります。ただし、Next.jsは自動コード分割や様々な最適化機能を提供しているため、適切に利用すればこの影響は最小限に抑えられます。
- Pages RouterとApp Routerの混在: Next.jsは現在、従来のPages Routerと新しいApp Routerという2つのルーティングシステムをサポートしています。App Routerが推奨されていますが、Pages Routerで書かれた既存のコードベースが存在する場合や、両方のシステムを混在させる必要がある場合、コードの管理や理解が複雑になる可能性があります。徐々にApp Routerへの移行が進むと考えられますが、移行期間中は注意が必要です。
これらのデメリットを理解した上で、プロジェクトの要件やチームのスキルセットに合わせてNext.jsが最適な選択肢であるかを判断することが重要です。しかし、多くのモダンなウェブアプリケーション開発のシナリオにおいては、Next.jsのメリットがデメリットを大きく上回る場合が多いでしょう。
Next.jsの導入準備
Next.jsプロジェクトを始める前に、いくつかの準備が必要です。
1. Node.jsのインストール
Next.jsはNode.js環境上で動作します。Node.jsにはパッケージマネージャーであるnpmが同梱されています。Next.jsを実行するには、Node.jsのバージョン18.17以降が必要です(推奨バージョンは20.6以降)。
まだNode.jsがインストールされていない場合、またはバージョンが古い場合は、公式ウェブサイトから最新の安定版(LTS版)をダウンロードしてインストールしてください。
インストール後、ターミナルまたはコマンドプロンプトを開き、以下のコマンドを実行してバージョンを確認します。
bash
node -v
npm -v
2. パッケージマネージャーの理解
npm以外にも、yarnやpnpmといったパッケージマネージャーがあります。これらはnpmと同様にJavaScriptのライブラリを管理しますが、インストール速度やディスク使用量などの点で違いがあります。どのパッケージマネージャーを使用してもNext.jsを開発できますが、プロジェクト内で統一することが推奨されます。
- npm: Node.jsに標準で付属。最も一般的。
- yarn: Facebook(現Meta)が開発。かつてはnpmより高速だったが、npm v5以降は速度差は縮小。
yarn install
のようにコマンドが異なる。 - pnpm: ディスク容量を効率的に使用できるのが特徴。特に大規模なプロジェクトやモノレポでメリットが大きい。
この記事では、特に指定がない限りnpmコマンドを例として使用しますが、他のパッケージマネージャーでも同様の操作が可能です。
3. 開発環境の構築
コードを書くためのテキストエディタまたは統合開発環境(IDE)が必要です。モダンなフロントエンド開発では、Visual Studio Code(VS Code)が広く利用されており、Next.jsやReact開発に役立つ多くの拡張機能が利用可能です。
VS Codeを利用する場合は、以下の拡張機能のインストールを検討すると良いでしょう。
- ESLint: JavaScript/TypeScriptのコード品質やスタイルをチェックし、問題を指摘してくれます。
- Prettier: コードのフォーマットを自動で整形してくれます。
- Tailwind CSS IntelliSense (Tailwind CSSを使う場合): Tailwind CSSのクラス名の補完やホバー時の情報表示をサポートします。
- React Developer Tools: Reactコンポーネントのツリーや状態をブラウザの開発者ツールで確認できます。
Next.jsプロジェクトの作成
準備が整ったら、いよいよNext.jsプロジェクトを作成します。Next.js公式が提供するcreate-next-app
というCLIツールを使用するのが最も簡単で推奨される方法です。このツールは、必要なディレクトリ構造や基本設定を含む新しいNext.jsアプリケーションのテンプレートを作成してくれます。
プロジェクトを作成したいディレクトリに移動し、ターミナルまたはコマンドプロンプトで以下のコマンドを実行します。
bash
npx create-next-app@latest my-nextjs-app
npx
:npm
v5.2以降に付属するツールで、ローカルにインストールされていないパッケージのCLIコマンドを実行できます。create-next-app
を一時的にダウンロードして実行します。create-next-app@latest
:create-next-app
ツールの最新バージョンを指定しています。my-nextjs-app
: 作成するプロジェクトのディレクトリ名です。好きな名前に変更してください。
コマンドを実行すると、いくつかの設定オプションについて質問されます。
“`
Need to install the following packages:
create-next-app@latest
Ok to proceed? (y) y
What is your project named? my-nextjs-app
Would you like to use TypeScript? (Yes/No) Yes
Would you like to use ESLint? (Yes/No) Yes
Would you like to use Tailwind CSS? (Yes/No) Yes
Would you like to use src/
directory? (Yes/No) No (またはYes、好みによる)
Would you like to use App Router? (Yes/No) Yes (推奨)
Would you like to customize the default import alias (@/*)? (Yes/No) No (またはYes、好みによる)
Creating a new Next.js app in /path/to/my-nextjs-app.
… 依存関係のインストールなどが行われます …
Success! Created my-nextjs-app at /path/to/my-nextjs-app
Inside that directory, you can run several commands:
npm run dev
Starts the development server.
npm run build
Builds the app for production.
npm run start
Runs the built app in production mode.
We suggest that you begin by typing:
cd my-nextjs-app
npm run dev
“`
ここでは、一般的なモダン開発の設定として、TypeScript、ESLint、Tailwind CSS、App Routerを「Yes」と選択しました。src/
ディレクトリの使用はプロジェクト構成の好みに合わせて選択してください。App RouterはNext.js 13以降の推奨ルーティングシステムなので、「Yes」を選択することを強く推奨します。
インストールが完了したら、表示されている案内に従ってプロジェクトディレクトリに移動し、開発サーバーを起動します。
bash
cd my-nextjs-app
npm run dev
開発サーバーが起動し、通常は http://localhost:3000
でアプリケーションにアクセスできるようになります。ブラウザでこのURLを開くと、Next.jsのウェルカムページが表示されるはずです。
これで、Next.jsプロジェクトの作成と開発環境の構築が完了しました!
プロジェクトディレクトリ構造(App Router使用時)
create-next-app
でApp Routerを選択した場合、プロジェクトの基本的なディレクトリ構造は以下のようになります。
my-nextjs-app/
├── app/ # アプリケーションコードのルート(App Router)
│ ├── (group)/ # ( ) はルーティングに影響しないディレクトリ(例: (marketing), (auth))
│ │ ├── layout.tsx # レイアウトコンポーネント
│ │ ├── page.tsx # ページコンポーネント
│ │ └── ...
│ ├── api/ # API Routes
│ │ ├── route.ts # APIエンドポイント
│ │ └── ...
│ ├── layout.tsx # ルートレイアウト(全てのページに適用される)
│ ├── page.tsx # ルートページ(`/` に対応)
│ ├── favicon.ico # ファビコン
│ └── global.css # グローバルスタイル
├── public/ # 静的ファイル(画像、フォントなど)
│ ├── next.svg
│ ├── vercel.svg
│ └── ...
├── next.config.js # Next.jsの設定ファイル
├── package.json # プロジェクトの依存関係とスクリプト
├── tsconfig.json # TypeScriptの設定ファイル (TypeScript選択時)
├── .eslintrc.json # ESLintの設定ファイル (ESLint選択時)
├── tailwind.config.ts # Tailwind CSSの設定ファイル (Tailwind CSS選択時)
├── postcss.config.js # PostCSSの設定ファイル (Tailwind CSS選択時)
└── README.md
app/
: App Routerを使用する場合、アプリケーションの全てのコードはこのディレクトリ以下に配置されます。ファイル名やディレクトリ名に基づいてルーティング、レイアウト、ローディングUI、エラーUIなどが定義されます。app/layout.tsx
: アプリケーション全体または特定のセグメントのレイアウトを定義します。App Routerを使用する場合、ルートのlayout.tsx
が必須です。このファイルは、HTMLの<html>
タグと<body>
タグを定義し、共有UI(ヘッダー、フッターなど)を配置します。app/page.tsx
: ルートパス (/
) に対応するページコンポーネントです。各ディレクトリにpage.tsx
(または.js
,.jsx
) ファイルを配置することで、そのディレクトリパスに対応するページが作成されます。app/api/
: API Routesを定義するディレクトリです。このディレクトリ以下のファイルはAPIエンドポイントとして扱われ、サーバーサイドのコードを実行できます。public/
: 静的なアセット(画像、フォント、動画など)を配置するディレクトリです。このディレクトリに配置されたファイルは、アプリケーションのルートパスから直接アクセスできます(例:public/image.png
は/image.png
でアクセス可能)。next.config.js
: Next.jsの挙動をカスタマイズするための設定ファイルです。環境変数、Rewrites, Redirects, Headersなどの設定を行います。package.json
: プロジェクトのメタデータ、依存ライブラリ、実行可能なスクプト(npm run dev
,npm run build
,npm run start
など)が定義されています。
この構造は規約に基づいていますが、非常に効率的で拡張性が高い設計になっています。
Next.jsの基本機能(App Router中心)
App RouterはNext.js 13.4で安定版となり、現在ではNext.jsでアプリケーションを開発する際の推奨される方法です。ここでは、App Routerにおける主要な機能について詳しく解説します。
1. ファイルシステムルーティング
App Routerにおけるルーティングは、app
ディレクトリ内のファイル構造に基づいて行われます。
-
ページ:
app
ディレクトリ内の各フォルダはURLセグメントに対応します。フォルダ内にpage.tsx
(または.js
,.jsx
) ファイルを配置すると、そのフォルダに対応するパスにアクセスした際にそのコンポーネントがレンダリングされます。app/dashboard/page.tsx
->/dashboard
app/settings/profile/page.tsx
->/settings/profile
app/page.tsx
->/
(ルートページ)
-
レイアウト:
app
ディレクトリ内のフォルダにlayout.tsx
(または.js
,.jsx
) ファイルを配置すると、そのフォルダ以下の全てのページに適用されるレイアウトが定義できます。レイアウトはネスト可能で、親レイアウトでラップされます。app/layout.tsx
: アプリケーション全体に適用されるルートレイアウト。app/dashboard/layout.tsx
:/dashboard
およびその子ルート(例:/dashboard/settings
)に適用されるレイアウト。
layout.tsx
コンポーネントはchildren
プロパティを受け取り、その中に子レイアウトまたはページがレンダリングされます。tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div>
<h2>Dashboard Layout</h2>
<nav>...</nav> {/* ダッシュボード固有のナビゲーション */}
<main>{children}</main> {/* 子ページまたは子レイアウトがここにレンダリングされる */}
</div>
);
} -
動的セグメント: パスの一部を動的にしたい場合は、フォルダ名を角括弧
[]
で囲みます。app/posts/[id]/page.tsx
:/posts/1
,/posts/abc
のようなパスに対応します。id
の値は、ページコンポーネントやレイアウトコンポーネントのparams
プロパティとして渡されます。
tsx
// app/posts/[id]/page.tsx
export default function PostPage({ params }: { params: { id: string } }) {
const postId = params.id;
// postId を使用して投稿データをフェッチするなど
return (
<div>
<h1>Post: {postId}</h1>
{/* ... */}
</div>
);
}
複数の動的セグメントを持つことも可能です (app/users/[userId]/posts/[postId]/page.tsx
)。 -
キャッチオールセグメント: 特定のパス以下の全てのセグメントを捕捉したい場合は、
[...slug]
のように記述します。app/docs/[...slug]/page.tsx
:/docs/a
,/docs/a/b
,/docs/a/b/c
のようなパスに対応します。slug
はパスセグメントの配列としてparams
に渡されます。- オプションで全てのセグメントを捕捉したい場合は
[[...slug]]
と記述します。これはパスが存在しない場合 (/docs
の場合) にもマッチします。
-
グループ化 (
()
): フォルダ名を丸括弧()
で囲むと、そのフォルダはURLパスとしては扱われず、ルーティングに影響しません。コードを論理的に整理したり、異なるレイアウトを持つセグメントをグループ化したりするのに役立ちます。app/(marketing)/about/page.tsx
->/about
app/(shop)/products/page.tsx
->/products
例えば、認証が必要なページと不要なページでレイアウトを分けたい場合に、
app/(dashboard)/...
とapp/(public)/...
のようにグループ化して、それぞれに異なるlayout.tsx
を配置するといった使い方ができます。
2. Server ComponentsとClient Components
App Routerの最も重要な概念の一つが、Server ComponentsとClient Componentsです。Next.jsはデフォルトでServer Componentsを使用します。
-
Server Components:
- サーバーサイドでレンダリングされ、初期HTMLに含まれてクライアントに送信されます。
- JavaScriptバンドルには含まれません(完全にサーバーサイドで実行される場合)。
- サーバーサイドでのデータフェッチ(データベースアクセス、API呼び出しなど)に直接アクセスできます。
- 機密性の高いコード(APIキーなど)をクライアントに露出させません。
- インタラクティブな機能(イベントハンドラー、state, effectなど)は使用できません。
- ファイル名の末尾に特定の拡張子や指定は不要です。デフォルトでServer Componentとして扱われます。
-
Client Components:
- クライアントサイドでレンダリングされます(初期ロード時にはサーバーでプリレンダリングされることもあります – Hydration)。
- ブラウザ上でインタラクティブな機能(クリックハンドラー、入力フォーム、state管理など)を提供できます。
- ブラウザAPI(
window
,localStorage
など)にアクセスできます。 - サーバーサイドのリソース(ファイルシステム、データベースなど)には直接アクセスできません。
- ファイルの先頭に
'use client';
ディレクティブを記述する必要があります。このディレクティブは、そのファイルとそのファイルからインポートされる全ての子コンポーネントがClient Componentであることを示します。
使い分けの基本:
- デフォルトはServer Components: 可能な限りServer Componentsを使用します。これにより、初期表示速度が向上し、クライアントに送信されるJavaScriptの量が削減され、パフォーマンスとSEOに有利です。
- インタラクティブな要素はClient Components: ボタンのクリック、フォームの入力、状態管理、ブラウザAPIへのアクセスなど、ユーザーとのインタラクションが必要なコンポーネントはClient Componentsとして定義します。
- データの場所で決める: サーバーサイドのリソースからデータをフェッチする場合はServer Component、クライアントサイドのリソース(ブラウザのStorageなど)やユーザー操作に応じてデータをフェッチする場合はClient Componentを使うことが多いです。
例:
“`tsx
// app/page.tsx (Server Component by default)
import ProductList from ‘./components/ProductList’; // Server Componentとしてインポート可能
import AddToCartButton from ‘./components/AddToCartButton’; // Client Componentとしてインポート可能
async function getProducts() {
// サーバーサイドでデータをフェッチ (API RoutesやDBアクセスなど)
const res = await fetch(‘https://api.example.com/products’, { cache: ‘no-store’ }); // 例: SSR
// const res = await fetch(‘https://api.example.com/products’, { next: { revalidate: 60 } }); // 例: ISR
// const res = await fetch(‘https://api.example.com/products’); // 例: SSG (デフォルト)
if (!res.ok) {
throw new Error(‘Failed to fetch data’);
}
return res.json();
}
export default async function HomePage() {
const products = await getProducts(); // Server Component内で直接async/awaitを使用可能
return (
Welcome to our Shop
{/ AddToCartButton はクリックイベントを持つため Client Component /}
);
}
“`
“`tsx
// app/components/AddToCartButton.tsx (‘use client’ ディレクティブが必要)
‘use client’;
import { useState } from ‘react’;
interface AddToCartButtonProps {
productId: string;
}
export default function AddToCartButton({ productId }: AddToCartButtonProps) {
const [isLoading, setIsLoading] = useState(false);
const handleClick = async () => {
setIsLoading(true);
// カートに追加する処理 (クライアントサイドで実行されるAPIコールなど)
await fetch(‘/api/cart’, {
method: ‘POST’,
body: JSON.stringify({ productId }),
});
setIsLoading(false);
};
return (
);
}
“`
Server ComponentsとClient Componentsの境界は非常に重要です。Server ComponentsはClient Componentsをインポートできますが、Client ComponentsはServer Componentsを直接インポートできません(Server Componentを子要素としてPropsで渡すことは可能)。
3. データフェッチング (App Router)
App Routerでは、データフェッチングの方法がPages Routerから大きく変更され、よりシンプルかつ柔軟になりました。主に以下の方法があります。
-
fetch
APIの拡張: Next.jsは組み込みのfetch
APIを拡張し、データのキャッシュ戦略を柔軟に制御できるようになりました。これはServer Components内で使用されます。- デフォルト (SSG):
fetch(url)
は、ビルド時にデータをフェッチし、結果をキャッシュします。同じリクエストが複数回発生する場合でも、ビルド時に一度だけフェッチされます。これはSSGと同様の挙動です。 - SSR:
fetch(url, { cache: 'no-store' })
またはfetch(url, { cache: 'reload' })
を使用すると、リクエストごとにデータをフェッチします。これはSSRと同様の挙動です。 - ISR:
fetch(url, { next: { revalidate: 60 } })
のようにrevalidate
オプションを指定すると、データがキャッシュされ、指定した秒数経過後にアクセスがあった際にバックグラウンドでデータを再フェッチしてキャッシュを更新します。これはISRと同様の挙動です。
- デフォルト (SSG):
-
Third-partyライブラリ: SWRやReact Queryのようなクライアントサイドでのデータフェッチングライブラリも、Client Components内で引き続き使用できます。これらは主にクライアントサイドでのキャッシュ管理やリアルタイム更新、ポーリングなどに役立ちます。
App Routerのデータフェッチングの特徴:
- Server Components内での
async
/await
: Server ComponentsはPromiseを返すことができ、async
/await
を使用して非同期にデータをフェッチできます。これにより、getStaticProps
やgetServerSideProps
のような専用のデータフェッチング関数は不要になりました。 - 並行データフェッチング: 同じルート内の複数のコンポーネントがそれぞれデータをフェッチする場合、デフォルトで並行して実行されます。これにより、ウォーターフォール問題を避け、ロード時間を短縮できます。
- Loading UI: データフェッチ中に表示するローディングUIを簡単に実装できます。ルーティングセグメントに対応するディレクトリに
loading.tsx
ファイルを作成すると、データフェッチ中に自動的にこのコンポーネントが表示されます。 - Error UI: データフェッチやレンダリング中にエラーが発生した場合に表示するUIを定義できます。ルーティングセグメントに対応するディレクトリに
error.tsx
ファイルを作成すると、そのセグメント内で発生したエラーがキャッチされ、このコンポーネントが表示されます。
4. API Routes (App Router)
App RouterでもAPI Routesは利用できます。Pages Routerでは pages/api
ディレクトリでしたが、App Routerでは app/api
ディレクトリを使用します。
- APIエンドポイントは
app/api
ディレクトリ内のフォルダ内にroute.ts
(または.js
,.jsx
) ファイルを作成することで定義します。 route.ts
ファイル内で、HTTPメソッドに対応する関数(GET
,POST
,PUT
,DELETE
,PATCH
,HEAD
,OPTIONS
)をエクスポートします。これらの関数はRequest
オブジェクトを受け取り、Response
オブジェクトを返します。
“`ts
// app/api/products/route.ts
import { NextResponse } from ‘next/server’;
// GET /api/products
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const category = searchParams.get(‘category’);
// データベースから商品をフェッチするなどの処理
const products = await fetchProducts(category); // 実際のデータフェッチ処理
return NextResponse.json(products); // JSONレスポンスを返す
}
// POST /api/products
export async function POST(request: Request) {
const data = await request.json();
const newProduct = await createProduct(data); // 実際のデータ作成処理
return NextResponse.json(newProduct, { status: 201 }); // ステータスコード201 (Created) を付けて返す
}
“`
API Routesはサーバーレス関数としてデプロイされることが多いため、データベース接続などはリクエストごとに確立する必要があります。
5. スタイル指定
Next.jsは様々なスタイリング方法をサポートしており、プロジェクトの要件や開発チームの好みに合わせて選択できます。
-
CSS Modules: ファイル名を
[name].module.css
とすることで、CSS Modulesとして扱われます。各クラス名が自動的にユニークな名前になるため、スタイルが衝突する心配がありません。コンポーネントごとにスタイルを管理するのに適しています。
css
/* styles/Button.module.css */
.button {
padding: 10px 20px;
background-color: blue;
color: white;
}
“`tsx
// components/Button.tsx
import styles from ‘../styles/Button.module.css’;export default function Button({ children }) {
return ;
}
“` -
Global CSS:
app/global.css
(App Router) またはpages/_app.js
(Pages Router) でインポートされたCSSファイルはグローバルスタイルとして扱われ、アプリケーション全体に適用されます。リセットCSSや共通のユーティリティクラスなどに使用します。 -
CSS-in-JS: Styled ComponentsやEmotionなどのライブラリも利用可能です。これらのライブラリはランタイムでスタイルを生成しますが、Next.jsはサーバーサイドでのレンダリングもサポートしているため、SSRでも正しくスタイルが適用されます。
-
Tailwind CSS: 近年人気が高まっているユーティリティファーストのCSSフレームワークです。
create-next-app
のセットアップ時に選択可能で、簡単に導入できます。設定ファイル(tailwind.config.ts
)でカスタマイズも容易です。
6. イメージ最適化 (next/image
)
next/image
コンポーネントは、Next.jsに組み込まれた高性能なイメージコンポーネントです。これを使用することで、画像の表示パフォーマンスを大幅に向上させることができます。
“`tsx
import Image from ‘next/image’;
import profilePic from ‘../public/profile.jpg’; // ローカル画像の場合
export default function ProfilePage() {
return (
My Profile
{/ ローカル画像 /}
{/* 外部URLの画像 */}
<Image
src="https://example.com/images/some-image.jpg"
alt="Some external image"
width={600}
height={400}
loader={({ src, width, quality }) => {
// 外部画像の場合、ローダー関数を定義してURLを生成することが推奨される
// 例: 画像CDNを使用する場合
return `${src}?w=${width}&q=${quality || 75}`;
}}
/>
</div>
);
}
“`
next/image
の主なメリット:
- サイズ最適化: デバイスのサイズやビューポートに合わせて画像を自動的にリサイズし、適切なサイズの画像を配信します。
- フォーマット変換: ブラウザがサポートしている場合、画像をWebPなどのモダンな軽量フォーマットに自動変換します。
- 遅延ロード (Lazy Loading): デフォルトで遅延ロードされるため、ビューポート外の画像はユーザーがスクロールして表示範囲に入るまで読み込まれません。これにより、初期ロード時間が短縮されます。
- レイアウトシフトの防止:
width
とheight
を指定することで、画像読み込み時のレイアウトシフトを防ぎます(CLSの改善)。 - 画像CDNとの連携: カスタムローダー関数を使用して、様々な画像CDNサービスと連携できます。
7. フォント最適化 (next/font
)
next/font
は、パフォーマンスとプライバシーを考慮したWebフォントの最適化機能です。Google Fontsとローカルフォントの両方をサポートします。
“`tsx
// app/layout.tsx (Google Fontsの例)
import { Inter } from ‘next/font/google’;
import ‘./global.css’;
// Interフォントのサブセットを自動的にホスト
const inter = Inter({ subsets: [‘latin’] });
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{/ font変数をclassNameに適用 /}
{children}
);
}
“`
next/font
のメリット:
- Automatic Self-Hosting: Google Fontsやローカルのフォントファイルを自動的にアプリケーションのオリジンからホストするため、外部CDNへのリクエストが不要になり、パフォーマンスとプライバシーが向上します。
- CLSの防止: フォントファイルがダウンロードされる前に代替フォントを表示し、ロード完了後にフォントを切り替えることで、テキストの点滅やレイアウトシフトを防ぎます。
- CSS
size-adjust
の自動適用: フォントのメトリクスを自動的に調整し、フォールバックフォントとWebフォントの切り替え時のレイアウトシフトをさらに軽減します。
8. スクリプト最適化 (next/script
)
Google Analytics, サードパーティのウィジェットなど、外部スクリプトをアプリケーションに組み込む際に使用します。スクリプトのロード戦略を制御し、ページのパフォーマンスへの影響を最小限に抑えることができます。
“`tsx
import Script from ‘next/script’;
export default function AnalyticsPage() {
return (
Analytics Page
{/ Google Analytics スクリプトの例 /}