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 バージョンをアップグレードする必要があります:
補足: 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 を導入しました。新しいルーターは 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 つの codemod があります:
next-image-to-legacy-image
codemod:next/image
のインポートを安全かつ自動的にnext/legacy/image
に名前変更します。既存のコンポーネントは同じ動作を維持します。next-image-experimental
codemod:インラインスタイルを危険に追加し、未使用の props を削除します。これにより、既存のコンポーネントの動作が新しいデフォルトに一致するように変更されます。この codemod を使用するには、最初にnext-image-to-legacy-image
codemod を実行する必要があります。
<Link>
コンポーネント
<Link>
コンポーネントは、子として手動で <a>
タグを追加する必要がなくなりました。この動作は version 12.2 で実験的オプションとして追加され、現在はデフォルトになっています。Next.js 13 では、<Link>
は常に <a>
をレンダリングし、基礎となるタグに props を転送できます。
例:
リンクを Next.js 13 にアップグレードするには、new-link
codemod を使用できます。
<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 などの React 機能を Next.js がどのように構築しているかを初めて使用する機会かもしれません。特殊ファイルやレイアウトなどの新しい 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 コンテキストプロバイダーを使用している場合は、クライアントコンポーネントに移動する必要があります。
getLayout()
パターンをレイアウトに移行(オプション)
Next.jsでは、pages
ディレクトリでページごとのレイアウトを実現するために、ページコンポーネントにプロパティを追加することをお勧めしていました。このパターンは、app
ディレクトリのネストされたレイアウトのネイティブサポートに置き換えることができます。
変更前後の例を参照
変更前
変更後
-
pages/dashboard/index.js
からPage.getLayout
プロパティを削除し、ページ移行のステップに従ってapp
ディレクトリに移動します。 -
DashboardLayout
の内容を、pages
ディレクトリの動作を保持するために新しいクライアントコンポーネントに移動します。 -
app
ディレクトリ内の新しいlayout.js
ファイルにDashboardLayout
をインポートします。 -
クライアントに送信するコンポーネントJavaScriptの量を減らすために、
DashboardLayout.js
(クライアントコンポーネント)の非対話的な部分をlayout.js
(サーバーコンポーネント)に徐々に移動できます。
ステップ 3: next/head
の移行
pages
ディレクトリでは、next/head
React コンポーネントを使用して、title
や meta
などの <head>
HTMLエレメントを管理していました。app
ディレクトリでは、next/head
は新しい組み込みSEOサポートに置き換えられます。
変更前:
変更後:
ステップ 4: ページの移行
app
ディレクトリのページは、デフォルトでサーバーコンポーネントです。これは、ページがクライアントコンポーネントであるpages
ディレクトリとは異なります。app
のデータフェッチが変更されました。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
からインポートされ、pages
のuseRouter
フック(next/router
からインポート)とは異なる動作をします。next/router
からインポートされたuseRouter
フックはapp
ディレクトリではサポートされていませんが、pages
ディレクトリでは引き続き使用できます。
- 新しい
useRouter
はpathname
文字列を返しません。代わりに別のusePathname
フックを使用してください。 - 新しい
useRouter
はquery
オブジェクトを返しません。検索パラメータと動的ルートパラメータは現在別々になっています。代わりにuseSearchParams
とuseParams
フックを使用してください。 useSearchParams
とusePathname
を一緒に使用して、ページ変更をリッスンできます。詳細はルーターイベントセクションを参照してください。- これらの新しいフックはクライアントコンポーネントでのみサポートされます。サーバーコンポーネントでは使用できません。
さらに、新しいuseRouter
フックには以下の変更があります:
isFallback
は削除されました。fallback
は置き換えられています。locale
、locales
、defaultLocales
、domainLocales
の値は削除されました。app
ディレクトリでは組み込みのi18n Next.js機能が不要になったためです。i18nの詳細はこちら。basePath
は削除されました。代替はuseRouter
の一部にはなりません。まだ実装されていません。asPath
は削除されました。新しいルーターからas
の概念が削除されたためです。isReady
は削除されました。もはや必要ありません。静的レンダリング中、useSearchParams()
フックを使用するコンポーネントは、プリレンダリングステップをスキップし、代わりにランタイム時にクライアント上でレンダリングされます。route
は削除されました。usePathname
またはuseSelectedLayoutSegments()
が代替を提供します。
pages
とapp
間でのコンポーネント共有
コンポーネントを pages
と app
ルーター間で互換性を保つには、next/compat/router
からの useRouter
フックを参照してください。
これは pages
ディレクトリからの useRouter
フックですが、ルーター間でコンポーネントを共有する際に使用することを意図しています。app
ルーターのみで使用する準備ができたら、next/navigation
からの新しい useRouter
に更新してください。
ステップ 6: データ取得メソッドの移行
pages
ディレクトリは、ページのデータを取得するために getServerSideProps
と getStaticProps
を使用します。app
ディレクトリ内では、これらの以前のデータ取得関数は、fetch()
と async
React サーバーコンポーネントに基づいたシンプルな API に置き換えられています。
サーバーサイドレンダリング(getServerSideProps
)
pages
ディレクトリでは、getServerSideProps
はサーバー上でデータをフェッチし、ファイル内のデフォルトでエクスポートされた React コンポーネントにプロップを転送するために使用されます。ページの初期 HTML はサーバーからプリレンダリングされ、その後ブラウザで「ハイドレーション」(インタラクティブ化)されます。
App Router では、サーバーコンポーネントを使用して、データ取得をReactコンポーネント内に配置できます。これにより、サーバーからレンダリングされたHTMLを維持しながら、クライアントに送信するJavaScriptを少なくすることができます。
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
オブジェクトの配列や解決されたパスの文字列ではなく、セグメントの配列となります。
generateStaticParams
という名称は、app
ディレクトリの新しいモデルにおいて、getStaticPaths
よりも適切です。get
プレフィックスは、getStaticProps
とgetServerSideProps
が不要になったため、より説明的なgenerate
に置き換えられています。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'
オプションを置き換えます。'blocking'
とtrue
の違いがストリーミングでほとんどないため、dynamicParams
にはfallback: 'blocking'
オプションは含まれていません。
dynamicParams
がtrue
(デフォルト)に設定されている場合、生成されていないルートセグメントがリクエストされると、サーバーでレンダリングされ、キャッシュされます。
増分静的再生成(revalidate
付きのgetStaticProps
)
pages
ディレクトリでは、getStaticProps
関数にrevalidate
フィールドを追加することで、一定時間後に自動的にページを再生成できます。
app
ディレクトリでは、fetch()
によるデータフェッチでrevalidate
を使用でき、指定された秒数だけリクエストをキャッシュします。
APIルート
APIルートはpages/api
ディレクトリで変更なく引き続き動作します。ただし、app
ディレクトリではルートハンドラに置き換えられています。
ルートハンドラを使用すると、Web RequestとResponse APIを使用して、特定のルートのカスタムリクエストハンドラを作成できます。
補足:以前クライアントから外部APIを呼び出すためにAPIルートを使用していた場合、現在はサーバーコンポーネントを使用してデータを安全にフェッチできます。データフェッチについてさらに詳しく学べます。
ステップ7:スタイリング
pages
ディレクトリでは、グローバルスタイルシートはpages/_app.js
にのみ制限されていました。app
ディレクトリではこの制限が解除され、グローバルスタイルは任意のレイアウト、ページ、またはコンポーネントに追加できます。
Tailwind CSS
Tailwind CSSを使用している場合、tailwind.config.js
ファイルにapp
ディレクトリを追加する必要があります:
また、グローバルスタイルをapp/layout.js
ファイルにインポートする必要があります:
Tailwind CSSでのスタイリングについてさらに詳しく学べます
Codemods
Next.jsは、機能が非推奨になった際にコードベースをアップグレードするためのCodemodトランスフォーメーションを提供しています。詳細についてはCodemodsを参照してください。