Pages RouterからApp Routerへの移行方法
このガイドでは次の内容を説明します:
- Next.jsアプリケーションをバージョン12からバージョン13に更新する
pages
ディレクトリとapp
ディレクトリの両方で動作する機能のアップグレード- 既存アプリケーションを
pages
からapp
へ段階的に移行する
アップグレード
Node.jsのバージョン
Node.jsの最低要件バージョンはv18.17になりました。詳細はNode.jsドキュメントを参照してください。
Next.jsのバージョン
Next.jsバージョン13に更新するには、お好みのパッケージマネージャーを使用して次のコマンドを実行します:
ESLintのバージョン
ESLintを使用している場合、ESLintのバージョンをアップグレードする必要があります:
補足: ESLintの変更を反映させるには、VS CodeでESLintサーバーを再起動する必要がある場合があります。コマンドパレット(Macでは
cmd+shift+p
、Windowsではctrl+shift+p
)を開き、ESLint: Restart ESLint Server
を検索してください。
次のステップ
更新が完了したら、次のセクションを参照してください:
- 新機能のアップグレード: ImageコンポーネントやLinkコンポーネントの改善など、新機能へのアップグレードガイド
pages
からapp
ディレクトリへの移行:pages
ディレクトリからapp
ディレクトリへ段階的に移行するステップバイステップガイド
新機能のアップグレード
Next.js 13では新しいApp Routerが導入され、新機能と規約が追加されました。新しいRouterはapp
ディレクトリで利用可能で、pages
ディレクトリと共存できます。
Next.js 13へのアップグレードはApp Routerの使用を必須としません。更新されたImageコンポーネント、Linkコンポーネント、Scriptコンポーネント、フォント最適化など、pages
ディレクトリでも動作する新機能を引き続き使用できます。
<Image/>
コンポーネント
Next.js 12では、next/future/image
という一時的なインポートでImageコンポーネントに新しい改善が導入されました。これらの改善には、クライアントサイドJavaScriptの削減、画像の拡張とスタイル設定の簡素化、アクセシビリティの向上、ネイティブブラウザの遅延読み込みなどが含まれます。
バージョン13では、この新しい動作がnext/image
のデフォルトになりました。
新しいImageコンポーネントへの移行を支援する2つのコードモードがあります:
next-image-to-legacy-image
コードモード:next/image
のインポートを安全かつ自動的にnext/legacy/image
にリネームします。既存のコンポーネントは同じ動作を維持します。next-image-experimental
コードモード: インラインスタイルを追加し、未使用のプロップを削除します。これにより既存コンポーネントの動作が新しいデフォルトに変更されます。このコードモードを使用するには、まずnext-image-to-legacy-image
コードモードを実行する必要があります。
<Link>
コンポーネント
<Link>
コンポーネントは、子要素として手動で<a>
タグを追加する必要がなくなりました。この動作はバージョン12.2で実験的なオプションとして追加され、現在はデフォルトになりました。Next.js 13では、<Link>
は常に<a>
をレンダリングし、基礎となるタグにプロップを転送できます。
例:
Next.js 13にリンクをアップグレードするには、new-link
コードモードを使用できます。
<Script>
コンポーネント
next/script
の動作がpages
とapp
の両方をサポートするように更新されましたが、スムーズな移行のためにいくつかの変更が必要です:
_document.js
に含めていたbeforeInteractive
スクリプトは、ルートレイアウトファイル(app/layout.tsx
)に移動してください。- 実験的な
worker
戦略はまだapp
で動作せず、この戦略で指定されたスクリプトは削除するか、別の戦略(例:lazyOnload
)を使用するように変更する必要があります。 onLoad
、onReady
、onError
ハンドラはサーバーコンポーネントでは動作しないため、クライアントコンポーネントに移動するか、完全に削除してください。
フォント最適化
以前、Next.jsはフォントCSSのインライン化によってフォントの最適化を支援していました。バージョン13では新しいnext/font
モジュールが導入され、優れたパフォーマンスとプライバシーを確保しながらフォント読み込み体験をカスタマイズできるようになりました。next/font
はpages
とapp
ディレクトリの両方でサポートされています。
CSSのインライン化はpages
では引き続き動作しますが、app
では動作しません。next/font
を使用してください。
next/font
の使用方法については、フォント最適化ページを参照してください。
pages
からapp
への移行
🎥 動画で学ぶ: App Routerの段階的な採用方法 → YouTube (16分).
App Routerへの移行は、サーバーコンポーネント、Suspenseなど、Next.jsが構築しているReact機能を初めて使用する機会かもしれません。特別なファイルやレイアウトなどの新しいNext.js機能と組み合わせると、移行には新しい概念、メンタルモデル、動作変更を学ぶ必要があります。
これらの更新を小さなステップに分割して複雑さを軽減することをお勧めします。app
ディレクトリは、pages
ディレクトリと同時に動作するように意図的に設計されており、ページごとに段階的に移行できます。
app
ディレクトリはネストされたルート_と_レイアウトをサポートします。詳細- ネストされたフォルダを使用してルートを定義し、特別な
page.js
ファイルを使用してルートセグメントを公開します。詳細 - 特別なファイル規約を使用して各ルートセグメントのUIを作成します。最も一般的な特別なファイルは
page.js
とlayout.js
です。page.js
を使用してルート固有のUIを定義します。layout.js
を使用して複数のルートで共有されるUIを定義します。- 特別なファイルには
.js
、.jsx
、.tsx
ファイル拡張子を使用できます。
- コンポーネント、スタイル、テストなど、他のファイルを
app
ディレクトリ内に配置できます。詳細 getServerSideProps
やgetStaticProps
などのデータ取得関数は、app
内の新しいAPIに置き換えられました。getStaticPaths
はgenerateStaticParams
に置き換えられました。pages/_app.js
とpages/_document.js
は単一のapp/layout.js
ルートレイアウトに置き換えられました。詳細pages/_error.js
はより細かいerror.js
特別ファイルに置き換えられました。詳細pages/404.js
はnot-found.js
ファイルに置き換えられました。pages/api/*
APIルートはroute.js
(ルートハンドラ)特別ファイルに置き換えられました。
ステップ1: app
ディレクトリの作成
最新のNext.jsバージョン(13.4以上が必要)に更新します:
次に、プロジェクトのルート(またはsrc/
ディレクトリ)に新しいapp
ディレクトリを作成します。
ステップ2: ルートレイアウトの作成
app
ディレクトリ内に新しいapp/layout.tsx
ファイルを作成します。これはルートレイアウトで、app
内のすべてのルートに適用されます。
app
ディレクトリには必ずルートレイアウトを含める必要があります。- Next.jsが自動的に作成しないため、ルートレイアウトは
<html>
と<body>
タグを定義する必要があります - ルートレイアウトは
pages/_app.tsx
とpages/_document.tsx
ファイルを置き換えます。 - レイアウトファイルには
.js
、.jsx
、.tsx
拡張子を使用できます。
<head>
HTML要素を管理するには、組み込みのSEOサポートを使用できます:
_document.js
と_app.js
の移行
既存の_app
または_document
ファイルがある場合、その内容(グローバルスタイルなど)をルートレイアウト(app/layout.tsx
)にコピーできます。app/layout.tsx
のスタイルはpages/*
には適用されません。pages/*
ルートが壊れないように、移行中は_app
/_document
を保持してください。完全に移行したら安全に削除できます。
React Contextプロバイダーを使用している場合、それらはクライアントコンポーネントに移動する必要があります。
getLayout()
パターンからレイアウトへの移行(オプション)
Next.jsでは、pages
ディレクトリでページごとのレイアウトを実現するためにページコンポーネントにプロパティを追加することを推奨していました。このパターンは、app
ディレクトリのネストされたレイアウトのネイティブサポートで置き換えることができます。
移行前後の例を見る
移行前
移行後
-
pages/dashboard/index.js
からPage.getLayout
プロパティを削除し、ページ移行の手順に従ってapp
ディレクトリに移行します。app/dashboard/page.js -
DashboardLayout
の内容を新しいクライアントコンポーネントに移動して、pages
ディレクトリの動作を維持します。app/dashboard/DashboardLayout.js -
DashboardLayout
をapp
ディレクトリ内の新しいlayout.js
ファイルにインポートします。app/dashboard/layout.js -
クライアントに送信するコンポーネントJavaScriptの量を減らすために、
DashboardLayout.js
(クライアントコンポーネント)の非インタラクティブ部分をlayout.js
(サーバーコンポーネント)に段階的に移動できます。
ステップ3: next/head
の移行
pages
ディレクトリでは、next/head
Reactコンポーネントを使用してtitle
やmeta
などの<head>
HTML要素を管理していました。app
ディレクトリでは、next/head
は新しい組み込みSEOサポートに置き換えられました。
移行前:
移行後:
ステップ4: ページの移行
app
ディレクトリのページはデフォルトでサーバーコンポーネント (Server Components)です。これはクライアントコンポーネント (Client Components)であるpages
ディレクトリのページとは異なります。app
ディレクトリではデータフェッチング (Data Fetching)が変更されています。getServerSideProps
、getStaticProps
、getInitialProps
はよりシンプルなAPIに置き換えられました。app
ディレクトリでは、ルートを定義するためにネストされたフォルダを使用し、特別なpage.js
ファイルを使用してルートセグメントを公開可能にします。-
pages
ディレクトリapp
ディレクトリルート index.js
page.js
/
about.js
about/page.js
/about
blog/[slug].js
blog/[slug]/page.js
/blog/post-1
ページの移行は以下の2つの主要なステップに分けることを推奨します:
- ステップ1: デフォルトでエクスポートされているページコンポーネントを新しいクライアントコンポーネントに移動する
- ステップ2: 新しいクライアントコンポーネントを
app
ディレクトリ内の新しいpage.js
ファイルにインポートする
補足: これは
pages
ディレクトリと最も動作が類似しているため、最も簡単な移行方法です。
ステップ1: 新しいクライアントコンポーネントを作成
app
ディレクトリ内に新しいファイル(例:app/home-page.tsx
など)を作成し、クライアントコンポーネントをエクスポートします。クライアントコンポーネントを定義するには、ファイルの先頭(インポート文の前)に'use client'
ディレクティブを追加します。- Pages Routerと同様に、最適化ステップがあり、初期ページロード時にクライアントコンポーネントを静的HTMLにプリレンダリングします。
pages/index.js
からデフォルトでエクスポートされているページコンポーネントをapp/home-page.tsx
に移動します。
ステップ2: 新しいページを作成
-
app
ディレクトリ内に新しいapp/page.tsx
ファイルを作成します。これはデフォルトでサーバーコンポーネントです。 -
home-page.tsx
クライアントコンポーネントをページにインポートします。 -
pages/index.js
でデータをフェッチしていた場合、データフェッチングロジックを新しいデータフェッチングAPIを使用してサーバーコンポーネントに直接移動します。詳細はデータフェッチングアップグレードガイドを参照してください。 -
以前のページで
useRouter
を使用していた場合は、新しいルーティングフックに更新する必要があります。詳細を確認。 -
開発サーバーを起動し、
http://localhost:3000
にアクセスします。既存のインデックスルートがappディレクトリを通じて提供されているのが確認できるはずです。
ステップ5: ルーティングフックの移行
app
ディレクトリの新しい動作をサポートするために、新しいルーターが追加されました。
app
ディレクトリでは、next/navigation
からインポートする3つの新しいフックを使用する必要があります:useRouter()
、usePathname()
、useSearchParams()
。
- 新しい
useRouter
フックはnext/navigation
からインポートされ、next/router
からインポートされるpages
ディレクトリのuseRouter
フックとは異なる動作をします。next/router
からインポートされるuseRouter
フックはapp
ディレクトリではサポートされていませんが、pages
ディレクトリでは引き続き使用できます。
- 新しい
useRouter
はpathname
文字列を返しません。代わりに別のusePathname
フックを使用してください。 - 新しい
useRouter
はquery
オブジェクトを返しません。検索パラメータと動的ルートパラメータは分離されました。代わりにuseSearchParams
とuseParams
フックを使用してください。 useSearchParams
とusePathname
を一緒に使用してページ変更を監視できます。詳細はルーターイベントセクションを参照してください。- これらの新しいフックはクライアントコンポーネントでのみサポートされています。サーバーコンポーネントでは使用できません。
さらに、新しいuseRouter
フックには以下の変更があります:
isFallback
は削除されました。fallback
は置き換えられました。locale
、locales
、defaultLocales
、domainLocales
の値は削除されました。app
ディレクトリではNext.jsの組み込みi18n機能は不要になったためです。i18nについて詳しく学ぶ。basePath
は削除されました。代替機能はuseRouter
の一部ではなく、まだ実装されていません。asPath
は削除されました。新しいルーターではas
の概念がなくなったためです。isReady
は不要になったため削除されました。静的レンダリング (Static Rendering)中に、useSearchParams()
フックを使用するコンポーネントはプリレンダリングステップをスキップし、代わりにクライアント側で実行時にレンダリングされます。route
は削除されました。代わりにusePathname
またはuseSelectedLayoutSegments()
を使用してください。
pages
とapp
間でのコンポーネント共有
pages
とapp
ルーター間でコンポーネントを互換性を持たせるには、next/compat/router
のuseRouter
フックを参照してください。
これはpages
ディレクトリのuseRouter
フックですが、ルーター間でコンポーネントを共有する際に使用することを意図しています。app
ルーターでのみ使用する準備ができたら、新しいnext/navigation
のuseRouter
に更新してください。
ステップ6: データフェッチングメソッドの移行
pages
ディレクトリでは、getServerSideProps
とgetStaticProps
を使用してページのデータをフェッチしていました。app
ディレクトリでは、これらの従来のデータフェッチング関数はfetch()
と非同期Reactサーバーコンポーネントを基盤としたよりシンプルなAPIに置き換えられました。
サーバーサイドレンダリング (getServerSideProps
)
pages
ディレクトリでは、getServerSideProps
を使用してサーバー上でデータをフェッチし、ファイル内のデフォルトでエクスポートされるReactコンポーネントにpropsとして渡していました。ページの初期HTMLはサーバーからプリレンダリングされ、その後ブラウザでページを「ハイドレート」(インタラクティブに)していました。
App Routerでは、サーバーコンポーネント (Server Components)内でデータフェッチングを直接行うことができます。これにより、クライアントに送信するJavaScriptを減らしながら、サーバーからレンダリングされたHTMLを維持できます。
cache
オプションをno-store
に設定することで、フェッチしたデータをキャッシュしないように指示できます。これはpages
ディレクトリのgetServerSideProps
と同様の動作です。
リクエストオブジェクトへのアクセス
pages
ディレクトリでは、Node.js HTTP APIに基づいてリクエストベースのデータを取得できました。
例えば、getServerSideProps
からreq
オブジェクトを取得し、それを使用してリクエストのクッキーやヘッダーを取得できました。
app
ディレクトリでは、リクエストデータを取得するための新しい読み取り専用関数が公開されています:
headers
: Web Headers APIに基づいており、サーバーコンポーネント内でリクエストヘッダーを取得するために使用できます。cookies
: Web Cookies APIに基づいており、サーバーコンポーネント内でクッキーを取得するために使用できます。
静的サイト生成 (getStaticProps
)
pages
ディレクトリでは、getStaticProps
関数を使用してビルド時にページをプリレンダリングしていました。この関数は外部APIやデータベースから直接データをフェッチし、ビルド時に生成されるページ全体にこのデータを渡すために使用されました。
app
ディレクトリでは、fetch()
を使用したデータフェッチングはデフォルトでcache: 'force-cache'
になり、手動で無効化されるまでリクエストデータをキャッシュします。これはpages
ディレクトリのgetStaticProps
と同様の動作です。
ダイナミックパス (getStaticPaths
)
pages
ディレクトリでは、getStaticPaths
関数を使用してビルド時にプリレンダリングするダイナミックパスを定義します。
app
ディレクトリでは、getStaticPaths
は generateStaticParams
に置き換えられます。
generateStaticParams
は getStaticPaths
と同様の動作をしますが、ルートパラメータを返すための簡素化されたAPIを提供し、レイアウト内で使用できます。generateStaticParams
の戻り値の形式は、ネストされた param
オブジェクトの配列や解決済みパスの文字列ではなく、セグメントの配列です。
app
ディレクトリの新しいモデルでは、getStaticPaths
よりも generateStaticParams
という名前が適切です。get
プレフィックスは、より説明的な generate
に置き換えられ、getStaticProps
や getServerSideProps
が不要になった現在では単独で適切です。Paths
サフィックスは、複数のダイナミックセグメントを持つネストされたルーティングにより適した Params
に置き換えられました。
fallback
の置き換え
pages
ディレクトリでは、getStaticPaths
から返される fallback
プロパティを使用して、ビルド時にプリレンダリングされていないページの動作を定義します。このプロパティは、ページ生成中にフォールバックページを表示する true
、404ページを表示する false
、またはリクエスト時にページを生成する blocking
に設定できます。
app
ディレクトリでは、config.dynamicParams
プロパティ が generateStaticParams
に含まれていないパラメータの処理方法を制御します:
true
: (デフォルト)generateStaticParams
に含まれていないダイナミックセグメントはオンデマンドで生成されます。false
:generateStaticParams
に含まれていないダイナミックセグメントは404を返します。
これは pages
ディレクトリの getStaticPaths
の fallback: true | false | 'blocking'
オプションを置き換えます。fallback: 'blocking'
オプションは dynamicParams
に含まれていません。ストリーミングでは 'blocking'
と true
の違いがほとんどないためです。
dynamicParams
を true
(デフォルト) に設定すると、生成されていないルートセグメントがリクエストされると、サーバーでレンダリングされキャッシュされます。
インクリメンタル静的再生成 (getStaticProps
の revalidate
)
pages
ディレクトリでは、getStaticProps
関数に revalidate
フィールドを追加して、一定時間後にページを自動的に再生成できます。
app
ディレクトリでは、fetch()
を使用したデータ取得で revalidate
を使用でき、指定された秒数間リクエストをキャッシュします。
API ルート
API ルートは pages/api
ディレクトリで変更なく引き続き動作します。ただし、app
ディレクトリでは ルートハンドラ に置き換えられています。
ルートハンドラを使用すると、Web の Request および Response API を使用して、特定のルートのカスタムリクエストハンドラを作成できます。
知っておくと良いこと: 以前にクライアントから外部APIを呼び出すためにAPIルートを使用していた場合、サーバーコンポーネント を使用して安全にデータを取得できるようになりました。データ取得 について詳しく学びましょう。
シングルページアプリケーション
シングルページアプリケーション (SPA) から Next.js に移行する場合は、ドキュメント を参照してください。
ステップ7: スタイリング
pages
ディレクトリでは、グローバルスタイルシートは pages/_app.js
に限定されていました。app
ディレクトリでは、この制限が解除され、グローバルスタイルは任意のレイアウト、ページ、またはコンポーネントに追加できます。
Tailwind CSS
Tailwind CSS を使用している場合は、tailwind.config.js
ファイルに app
ディレクトリを追加する必要があります:
また、app/layout.js
ファイルでグローバルスタイルをインポートする必要があります:
Tailwind CSS を使ったスタイリング について詳しく学びましょう
App Router と Pages Router の併用
異なる Next.js ルーターによって提供されるルート間をナビゲートする場合、ハードナビゲーションが発生します。next/link
による自動リンクプリフェッチは、ルーター間ではプリフェッチされません。
代わりに、App Router と Pages Router 間のナビゲーションを最適化して、プリフェッチと高速なページ遷移を維持できます。詳細を学ぶ
コードモッド
Next.js は、機能が非推奨になったときにコードベースをアップグレードするためのコードモッド変換を提供します。詳細については コードモッド を参照してください。