Create React App から Next.js への移行方法
このガイドでは、既存の Create React App (CRA) のサイトを Next.js に移行する方法を説明します。
移行する理由
Create React App から Next.js に移行する理由には、以下のようなものがあります:
初期ページ読み込みの遅さ
Create React App は純粋なクライアントサイドの React を使用しています。シングルページアプリケーション (SPA) として知られるクライアントサイドのみのアプリケーションでは、初期ページの読み込みが遅くなる傾向があります。これは以下の理由で発生します:
- ブラウザは、データ読み込みのリクエストを送信できるようになる前に、React コードとアプリケーション全体のバンドルがダウンロードされ実行されるのを待つ必要があります。
- 新しい機能や依存関係を追加するたびに、アプリケーションコードが肥大化します。
自動コード分割の欠如
前述の読み込み遅延の問題は、コード分割である程度軽減できます。しかし、手動でコード分割を実施すると、意図せずネットワークウォーターフォールを引き起こす可能性があります。Next.js にはルーターとビルドパイプラインに組み込まれた自動コード分割とツリーシェイキングが備わっています。
ネットワークウォーターフォール
パフォーマンス低下の一般的な原因は、アプリケーションがデータを取得するためにクライアント-サーバー間で順次リクエストを行う場合です。SPA でのデータ取得パターンの1つは、プレースホルダーをレンダリングし、コンポーネントがマウントされた後にデータを取得する方法です。残念ながら、子コンポーネントは親コンポーネントが自身のデータの読み込みを完了した後にのみデータ取得を開始できるため、リクエストの「ウォーターフォール」が発生します。
Next.js でもクライアントサイドのデータ取得はサポートされていますが、Next.js ではデータ取得をサーバー側に移行することも可能です。これにより、クライアント-サーバー間のウォーターフォールを完全に排除できる場合があります。
高速で意図的なローディング状態
React Suspense を使ったストリーミングの組み込みサポートにより、UI のどの部分をどの順序で最初に読み込むかを定義でき、ネットワークウォーターフォールを作成することなく実現できます。
これにより、読み込みが速く、レイアウトシフトのないページを構築できます。
データ取得戦略の選択
Next.js では、必要に応じてページまたはコンポーネントレベルでデータ取得戦略を選択できます。例えば、CMS からデータを取得しブログ投稿をビルド時にレンダリングする(SSG)ことで高速な読み込みを実現したり、必要に応じてリクエスト時にデータを取得する(SSR)ことが可能です。
ミドルウェア
Next.js ミドルウェアを使用すると、リクエストが完了する前にサーバー上でコードを実行できます。例えば、認証が必要なページに対してミドルウェアでログインページにリダイレクトすることで、未認証コンテンツのフラッシュを防げます。また、A/B テスト、実験、国際化 (i18n) などの機能にも使用できます。
組み込みの最適化
画像、フォント、サードパーティスクリプトは、アプリケーションのパフォーマンスに大きな影響を与えることがよくあります。Next.js には、これらを自動的に最適化する専用のコンポーネントと API が含まれています。
移行手順
私たちの目標は、できるだけ早く動作する Next.js アプリケーションを取得し、その後段階的に Next.js の機能を採用できるようにすることです。最初に、既存のルーターをすぐに置き換えることなく、アプリケーションを純粋なクライアントサイドアプリケーション (SPA) として扱います。これにより、複雑さとマージコンフリクトを減らせます。
注: カスタム
homepage
フィールドをpackage.json
に設定している、カスタムサービスワーカーを使用している、または特定の Babel/webpack 調整を行っているなど、高度な CRA 構成を使用している場合は、このガイドの最後にある追加の考慮事項セクションを参照し、Next.js でこれらの機能を複製または適応するためのヒントを確認してください。
ステップ 1: Next.js 依存関係のインストール
既存のプロジェクトに Next.js をインストールします:
ステップ 2: Next.js 設定ファイルの作成
プロジェクトのルート (package.json
と同じレベル) に next.config.ts
を作成します。このファイルには Next.js の設定オプション が含まれます。
注:
output: 'export'
を使用すると、静的エクスポートを行います。SSR や API などのサーバーサイド機能にはアクセスできません。この行を削除すると、Next.js のサーバー機能を活用できます。
ステップ 3: ルートレイアウトの作成
Next.js の App Router アプリケーションには、すべてのページをラップする ルートレイアウト ファイル (React Server Component) を含める必要があります。
CRA アプリケーションでルートレイアウトファイルに最も近いのは public/index.html
で、<html>
、<head>
、<body>
タグが含まれています。
src
フォルダ内 (またはプロジェクトルートにapp
を配置したい場合はルートに) 新しいapp
ディレクトリを作成します。app
ディレクトリ内にlayout.tsx
(またはlayout.js
) ファイルを作成します:
次に、古い index.html
の内容をこの <RootLayout>
コンポーネントにコピーします。body div#root
(および body noscript
) を <div id="root">{children}</div>
に置き換えます。
豆知識: Next.js はデフォルトで CRA の
public/manifest.json
、追加のアイコン、テスト設定 を無視します。これらが必要な場合、Next.js には Metadata API と テスト 設定のサポートがあります。
ステップ 4: メタデータ
Next.js は自動的に <meta charset="UTF-8" />
と <meta name="viewport" content="width=device-width, initial-scale=1" />
タグを含めるため、<head>
からこれらを削除できます:
favicon.ico
、icon.png
、robots.txt
などの メタデータファイル は、app
ディレクトリの最上位に配置されている限り、自動的にアプリケーションの <head>
タグに追加されます。サポートされているすべてのファイル を app
ディレクトリに移動した後、<link>
タグを安全に削除できます:
最後に、Next.js は Metadata API で最後の <head>
タグを管理できます。最後のメタデータ情報をエクスポートされた metadata
オブジェクト に移動します:
上記の変更により、index.html
ですべてを宣言する方法から、フレームワークに組み込まれた Next.js の規約ベースのアプローチ (Metadata API) に移行しました。このアプローチにより、ページの SEO とウェブ共有性をより簡単に向上させられます。
ステップ 5: スタイル
CRA と同様に、Next.js は CSS Modules をすぐに使える形でサポートしています。また、グローバル CSS のインポート もサポートしています。
グローバル CSS ファイルがある場合は、app/layout.tsx
にインポートします:
Tailwind CSS を使用している場合は、インストールドキュメント を参照してください。
ステップ 6: エントリポイントページの作成
Create React App は src/index.tsx
(または index.js
) をエントリポイントとして使用します。Next.js (App Router) では、app
ディレクトリ内の各フォルダがルートに対応し、各フォルダには page.tsx
が必要です。
現在のところアプリを SPA として維持し、すべてのルートをインターセプトしたいため、オプションのキャッチオールルート を使用します。
app
内に[[...slug]]
ディレクトリを作成します。
page.tsx
に以下を追加します:
これにより、Next.js は空のスラッグ (/
) に対して単一のルートを生成し、すべてのルートを同じページにマッピングします。このページは Server Component で、静的 HTML にプリレンダリングされます。
ステップ 7: クライアント専用エントリポイントの追加
次に、CRA のルート App コンポーネントを Client Component 内に埋め込み、すべてのロジックをクライアントサイドに維持します。Next.js を初めて使用する場合、クライアントコンポーネントは (デフォルトでは) サーバー上でプリレンダリングされることに注意してください。これらは、クライアントサイド JavaScript を実行する追加機能を持つものと考えることができます。
app/[[...slug]]/
内に client.tsx
(または client.js
) を作成します:
'use client'
ディレクティブにより、このファイルは Client Component になります。dynamic
インポートとssr: false
により、<App />
コンポーネントのサーバーサイドレンダリングが無効になり、真のクライアント専用 (SPA) になります。
次に、page.tsx
(または page.js
) を更新して新しいコンポーネントを使用します:
ステップ8: 静的画像インポートの更新
CRAでは、画像ファイルをインポートすると公開URLが文字列として返されます:
Next.jsでは、静的画像インポートはオブジェクトを返します。このオブジェクトはNext.jsの<Image>
コンポーネントで直接使用するか、既存の<img>
タグでオブジェクトのsrc
プロパティを使用できます。
<Image>
コンポーネントには自動画像最適化という追加の利点があります。<Image>
コンポーネントは画像の寸法に基づいて結果の<img>
のwidth
とheight
属性を自動的に設定します。これにより、画像の読み込み時にレイアウトシフトが防止されます。ただし、片方の寸法のみがスタイリングされ、もう一方がauto
にスタイリングされていない画像がアプリに含まれている場合、問題が発生する可能性があります。auto
にスタイリングされていない場合、寸法は<img>
のdimension属性の値にデフォルト設定され、画像が歪んで表示される可能性があります。
<img>
タグを維持すると、アプリケーションの変更量を減らし、上記の問題を防ぐことができます。その後、必要に応じてローダーの設定を行って<Image>
コンポーネントに移行し、画像最適化を活用するか、自動画像最適化を備えたデフォルトのNext.jsサーバーに移行できます。
/public
からインポートした画像の絶対インポートパスを相対インポートに変換:
<img>
タグに画像オブジェクト全体ではなくsrc
プロパティを渡す:
または、ファイル名に基づいて画像アセットの公開URLを参照できます。例えば、public/logo.png
はアプリケーションで/logo.png
として画像を提供し、これがsrc
値になります。
警告: TypeScriptを使用している場合、
src
プロパティにアクセスすると型エラーが発生する可能性があります。これを修正するには、tsconfig.json
ファイルのinclude
配列にnext-env.d.ts
を追加する必要があります。Next.jsはステップ9でアプリケーションを実行するとこのファイルを自動生成します。
ステップ9: 環境変数の移行
Next.jsはCRAと同様に環境変数をサポートしていますが、ブラウザに公開したい変数には必ずNEXT_PUBLIC_
プレフィックスが必要です。
主な違いは、クライアントサイドで環境変数を公開するために使用されるプレフィックスです。REACT_APP_
プレフィックスを持つすべての環境変数をNEXT_PUBLIC_
に変更してください。
ステップ10: package.json
のスクリプト更新
package.json
のスクリプトをNext.jsコマンドを使用するように更新します。また、.next
とnext-env.d.ts
を.gitignore
に追加します:
これで次のコマンドを実行できます:
http://localhost:3000を開きます。Next.jsで実行されているアプリケーション(SPAモード)が表示されるはずです。
ステップ11: クリーンアップ
Create React Appに固有のアーティファクトを削除できます:
public/index.html
src/index.tsx
src/react-app-env.d.ts
reportWebVitals
の設定react-scripts
依存関係(package.json
からアンインストール)
追加の考慮事項
CRAでのカスタムhomepage
の使用
CRAのpackage.json
でhomepage
フィールドを使用して特定のサブパスでアプリを提供していた場合、next.config.ts
でbasePath
設定を使用してNext.jsで再現できます:
カスタムService Worker
の処理
CRAのサービスワーカー(例: create-react-app
のserviceWorker.js
)を使用していた場合、Next.jsでプログレッシブウェブアプリケーション(PWA)を作成する方法を学べます。
APIリクエストのプロキシ
CRAアプリがpackage.json
のproxy
フィールドを使用してバックエンドサーバーにリクエストを転送していた場合、next.config.ts
でNext.jsリライトを使用して再現できます:
カスタムWebpack/Babel設定
CRAでカスタムWebpackまたはBabel設定を持っていた場合、next.config.ts
でNext.jsの設定を拡張できます:
注記: これには
dev
スクリプトから--turbopack
を削除してTurbopackを無効にする必要があります。
TypeScript設定
Next.jsはtsconfig.json
がある場合、自動的にTypeScriptを設定します。next-env.d.ts
がtsconfig.json
のinclude
配列にリストされていることを確認してください:
バンドラーの互換性
Create React AppとNext.jsはどちらもデフォルトでwebpackを使用してバンドリングします。Next.jsはローカル開発を高速化するためにTurbopackも提供しています:
CRAから高度なwebpack設定を移行する必要がある場合は、カスタムwebpack設定を提供できます。
次のステップ
すべてが機能していれば、シングルページアプリケーションとして動作するNext.jsアプリケーションができています。まだサーバーサイドレンダリングやファイルベースルーティングなどのNext.js機能を活用していませんが、段階的に導入できます:
- React Routerから移行してNext.js App Routerを使用:
- 自動コード分割
- ストリーミングサーバーレンダリング
- Reactサーバーコンポーネント
<Image>
コンポーネントで画像を最適化next/font
でフォントを最適化<Script>
コンポーネントでサードパーティスクリプトを最適化npx next lint
を実行してNext.js推奨ルールでESLintを有効化し、プロジェクトのニーズに合わせて設定
注記: 静的エクスポート(
output: 'export'
)の使用は現在、useParams
フックや他のサーバー機能をサポートしていません。すべてのNext.js機能を使用するには、next.config.ts
からoutput: 'export'
を削除してください。