Viteからの移行
このガイドは、既存のViteアプリケーションを Next.js に移行するのに役立ちます。
なぜ乗り換えるのか?
Vite から Next.js に乗り換える理由はいくつかあります:
初期ページ読み込み時間が遅い
React用のデフォルトViteプラグインでアプリケーションを構築した場合、アプリケーションは純粋なクライアントサイドアプリケーションになります。クライアントサイド専用のアプリケーション(いわゆるシングルページアプリケーション、SPA)は、初期ページ読み込み時間が遅くなることがよくあります。これは以下の理由によって発生します:
- ブラウザは、Reactコードと全アプリケーションバンドルをダウンロードして実行するまで待つ必要があり、その後にデータを読み込むリクエストを送信できます。
- 新機能や追加の依存関係を追加するたびに、アプリケーションコードが拡大します。
自動コード分割がない
遅い読み込み時間の問題は、コード分割である程度管理できます。しかし、手動でコード分割を試みると、パフォーマンスが悪化することがよくあります。手動でコード分割を行うと、ネットワークウォーターフォールを不注意に導入しやすくなります。Next.jsは、ルーターに組み込まれた自動コード分割を提供します。
ネットワークウォーターフォール
パフォーマンスが低下する一般的な原因は、アプリケーションがデータを取得するためにシーケンシャルなクライアント-サーバーリクエストを行う場合です。SPAのデータ取得における一般的なパターンは、最初にプレースホルダーをレンダリングし、コンポーネントがマウントされた後にデータを取得することです。残念ながら、これは、データを取得する子コンポーネントが、親コンポーネントが独自のデータの読み込みを完了するまでデータ取得を開始できないことを意味します。
Next.jsはクライアント上でのデータ取得をサポートしていますが、データ取得をサーバーに移行するオプションも提供し、クライアント-サーバーウォーターフォールを排除できます。
高速で意図的な読み込み状態
React Suspenseを介したストリーミングの組み込みサポートにより、ネットワークウォーターフォールを導入することなく、UIのどの部分を最初にどの順序で読み込みたいかをより意図的に制御できます。
これにより、読み込みが速いページを構築し、レイアウトシフトを排除できます。
データ取得戦略の選択
ニーズに応じて、Next.jsではページおよびコンポーネントごとにデータ取得戦略を選択できます。ビルド時、サーバー上のリクエスト時、またはクライアント上でデータを取得するかを決定できます。例えば、CMSからデータを取得してブログ投稿をビルド時にレンダリングし、CDNで効率的にキャッシュできます。
ミドルウェア
Next.jsミドルウェアにより、リクエストが完了する前にサーバー上でコードを実行できます。これは、認証済みページにアクセスした際に未認証のコンテンツが一瞬表示されるのを避けるため、ユーザーをログインページにリダイレクトする場合に特に便利です。ミドルウェアは実験や国際化にも役立ちます。
組み込みの最適化
画像、フォント、サードパーティスクリプトは、アプリケーションのパフォーマンスに大きな影響を与えることがよくあります。Next.jsは、それらを自動的に最適化する組み込みのコンポーネントを提供します。
移行手順
この移行の目標は、できるだけ早く動作する Next.js アプリケーションを作成し、その後 Next.js の機能を徐々に採用できるようにすることです。まず、既存のルーターを移行せずに、純粋なクライアントサイドアプリケーション(SPA)として保持します。これにより、移行プロセス中の問題発生の可能性を最小限に抑え、マージコンフリクトを減らすことができます。
ステップ 1: Next.js 依存関係のインストール
まず、next
を依存関係としてインストールする必要があります:
ステップ 2: Next.js 設定ファイルの作成
プロジェクトのルートに next.config.mjs
を作成します。このファイルにはNext.jsの設定オプションを記述します。
補足: Next.js 設定ファイルには
.js
または.mjs
のいずれかを使用できます。
ステップ 3: TypeScript 設定の更新
TypeScriptを使用している場合、Next.jsと互換性を持たせるために tsconfig.json
ファイルを以下のように更新する必要があります。TypeScriptを使用していない場合は、このステップをスキップできます。
- プロジェクト参照を
tsconfig.node.json
から削除 include
配列に./dist/types/**/*.ts
と./next-env.d.ts
を追加exclude
配列に./node_modules
を追加compilerOptions
のplugins
配列に{ "name": "next" }
を追加esModuleInterop
をtrue
に設定:"esModuleInterop": true
jsx
をpreserve
に設定:"jsx": "preserve"
allowJs
をtrue
に設定:"allowJs": true
forceConsistentCasingInFileNames
をtrue
に設定:"forceConsistentCasingInFileNames": true
incremental
をtrue
に設定:"incremental": true
以下は、これらの変更を加えた tsconfig.json
の例です:
TypeScriptの設定に関する詳細は、Next.jsドキュメントを参照してください。
ステップ 4: ルートレイアウトの作成
Next.js App Router アプリケーションには、アプリケーション内のすべてのページをラップするルートレイアウトファイルが必要です。これはReactサーバーコンポーネントで、app
ディレクトリの最上位に定義されます。
Viteアプリケーションにおけるルートレイアウトファイルに最も近いものは、<html>
、<head>
、<body>
タグを含む index.html
ファイルです。
このステップでは、index.html
ファイルをルートレイアウトファイルに変換します:
src
ディレクトリ内に新しいapp
ディレクトリを作成します。- その
app
ディレクトリ内に新しいlayout.tsx
ファイルを作成します:
補足: レイアウトファイルには
.js
、.jsx
、または.tsx
の拡張子を使用できます。
- 以前作成した
<RootLayout>
コンポーネントにindex.html
ファイルの内容をコピーし、body.div#root
とbody.script
タグを<div id="root">{children}</div>
に置き換えます:
- Next.jsはデフォルトでmeta charsetとmeta viewportタグを含んでいるため、
<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:エントリポイントページの作成
Next.jsでは、page.tsx
ファイルを作成することでアプリケーションのエントリポイントを宣言します。このファイルはViteの main.tsx
ファイルに最も近いものです。このステップでは、アプリケーションのエントリポイントを設定します。
app
ディレクトリに[[...slug]]
ディレクトリを作成します。
このガイドでは、Next.jsをSPA(シングルページアプリケーション)として設定することを目指すため、アプリケーションのすべての可能なルートをキャッチするページエントリポイントが必要です。そのため、app
ディレクトリに新しい [[...slug]]
ディレクトリを作成します。
このディレクトリはオプションのキャッチオールルートセグメントと呼ばれます。Next.jsはディレクトリを使用してルートを定義するファイルシステムベースのルーターを使用しています。この特殊なディレクトリにより、アプリケーションのすべてのルートがそのディレクトリ内の page.tsx
ファイルに転送されます。
app/[[...slug]]
ディレクトリ内に以下の内容の新しいpage.tsx
ファイルを作成します:
補足: ページファイルには
.js
、.jsx
、または.tsx
拡張子を使用できます。
このファイルはサーバーコンポーネントです。next build
を実行すると、このファイルは静的アセットにプリレンダリングされます。動的コードは必要ありません。
このファイルはグローバルCSSをインポートし、generateStaticParams
に、インデックスルート /
のみを生成することを伝えます。
次に、クライアント専用で実行される Vite アプリケーションの残りの部分を移動します。
このファイルは 'use client'
ディレクティブで定義されたクライアントコンポーネントです。クライアントコンポーネントは、クライアントに送信される前に、依然としてHTMLにプリレンダリングされます。
クライアントのみのアプリケーションを開始するため、App
コンポーネントからのプリレンダリングを無効にするようNext.jsを設定できます。
次に、新しいコンポーネントを使用するようにエントリポイントページを更新します:
ステップ6:静的画像インポートの更新
Next.jsは静的画像のインポートをViteとは少し異なる方法で処理します。Viteでは、画像ファイルをインポートするとその公開URLが文字列として返されます:
Next.jsでは、静的画像のインポートはオブジェクトを返します。このオブジェクトは、Next.jsの<Image>
コンポーネントで直接使用できるか、既存の<img>
タグでsrc
プロパティを使用できます。
<Image>
コンポーネントは自動画像最適化の追加メリットがあります。<Image>
コンポーネントは、画像の寸法に基づいて結果の<img>
タグのwidth
とheight
属性を自動的に設定します。これにより、画像の読み込み時のレイアウトシフトを防ぎます。ただし、アプリケーションに片方の寸法のみがスタイル設定され、もう片方がauto
にスタイル設定されていない画像が含まれている場合、問題が発生する可能性があります。auto
にスタイル設定されていない場合、寸法はデフォルトで<img>
タグの寸法属性の値になり、画像が歪んで表示される可能性があります。
<img>
タグを維持することで、アプリケーション内の変更点を減らし、上記の問題を防ぐことができます。その後、ローダーを設定するか、自動画像最適化を備えたデフォルトのNext.jsサーバーに移行することで、任意で後から<Image>
コンポーネントに移行し、画像を最適化できます。
/public
からインポートされた画像の絶対インポートパスを相対インポートに変換します:
<img>
タグに画像オブジェクト全体ではなく、src
プロパティを渡します:
または、ファイル名に基づいて画像アセットの公開URLを参照することもできます。例えば、public/logo.png
はアプリケーションで/logo.png
として画像を提供し、これがsrc
値になります。
警告: TypeScriptを使用している場合、
src
プロパティにアクセスする際に型エラーが発生する可能性があります。現時点では安全に無視できます。このガイドの最後には修正されます。
ステップ7:環境変数の移行
Next.jsは、Viteと同様に.env
環境変数をサポートしています。主な違いは、クライアント側に環境変数を公開するために使用される接頭辞です。
VITE_
接頭辞の付いたすべての環境変数をNEXT_PUBLIC_
に変更します。
Viteは特別なimport.meta.env
オブジェクト上にいくつかの組み込み環境変数を公開しますが、これらはNext.jsではサポートされていません。以下のように使用法を更新する必要があります:
import.meta.env.MODE
⇒process.env.NODE_ENV
import.meta.env.PROD
⇒process.env.NODE_ENV === 'production'
import.meta.env.DEV
⇒process.env.NODE_ENV !== 'production'
import.meta.env.SSR
⇒typeof window !== 'undefined'
Next.jsは組み込みのBASE_URL
環境変数を提供しません。しかし、必要に応じて設定することは可能です:
- 次の内容を
.env
ファイルに追加します:
next.config.mjs
ファイルでbasePath
をprocess.env.NEXT_PUBLIC_BASE_PATH
に設定します:
import.meta.env.BASE_URL
の使用箇所をprocess.env.NEXT_PUBLIC_BASE_PATH
に更新します
ステップ8:package.json
のスクリプトを更新
これで、Next.jsへの移行が成功したかテストするためにアプリケーションを実行できるようになりました。ただし、その前に、package.json
のスクリプトをNext.js関連のコマンドに更新し、.next
とnext-env.d.ts
を.gitignore
に追加する必要があります:
npm run dev
を実行し、http://localhost:3000
を開きます。Next.jsでアプリケーションが実行されているはずです。
例: Next.jsに移行されたViteアプリケーションの実際の例については、このプルリクエストを確認してください。
ステップ9:クリーンアップ
これで、Viteに関連する成果物をコードベースからクリーンアップできます:
main.tsx
を削除index.html
を削除vite-env.d.ts
を削除tsconfig.node.json
を削除vite.config.ts
を削除- Viteの依存関係をアンインストール
次のステップ
計画通りに進めば、シングルページアプリケーションとして実行されるNext.jsアプリケーションが稼働しているはずです。ただし、まだNext.jsの利点のほとんどを活用できていませんが、今後段階的に変更を加えることで、すべての利点を得ることができます。次に行うことは以下のようなものです:
- React RouterからNext.jsのApp Routerに移行して以下を取得:
- 自動コード分割
- ストリーミングサーバーレンダリング
- Reactサーバーコンポーネント
<Image>
コンポーネントで画像を最適化next/font
でフォントを最適化<Script>
コンポーネントでサードパーティスクリプトを最適化- Next.jsルールをサポートするようにESLint設定を更新