Create React App からの移行
このガイドは、既存の Create React App サイトを Next.js に移行するのに役立ちます。
なぜ切り替えるのか?
Create React App から Next.js に切り替えたい理由はいくつかあります。
初期ページ読み込み時間の遅さ
Create React App は、純粋にクライアントサイドの React を使用します。シングルページアプリケーション (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
をインストールする必要があります。
npm install next@latest
ステップ 2: Next.js 構成ファイルを作成する
プロジェクトのルートにnext.config.mjs
を作成します。このファイルには、Next.js 構成オプションが保持されます。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './build', // Changes the build output directory to `./dist`.
}
export default nextConfig
ステップ 3: ルートレイアウトを作成する
Next.js のApp Router アプリケーションには、アプリケーション内のすべてのページをラップするルートレイアウトファイルが必要です。これは、React サーバーコンポーネントであり、app
ディレクトリの最上位レベルで定義されます。
CRA アプリケーションのルートレイアウトファイルに最も近いものは、<html>
、<head>
、および<body>
タグを含むindex.html
ファイルです。
このステップでは、index.html
ファイルをルートレイアウトファイルに変換します。
src
ディレクトリに新しいapp
ディレクトリを作成します。- その
app
ディレクトリの中に新しいlayout.tsx
ファイルを作成します。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return '...'
}
知っておくと良いこと: レイアウトファイルには、
.js
、.jsx
、または.tsx
拡張子を使用できます。
index.html
ファイルの内容を、以前に作成した<RootLayout>
コンポーネントにコピーし、body.div#root
およびbody.noscript
タグを<div id="root">{children}</div>
に置き換えます。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<meta charSet="UTF-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
知っておくと良いこと: Next.js は、CRA の
public/manifest.json
ファイル、追加のアイコン (favicon
、icon
、およびapple-icon
を除く) 、およびテスト構成を無視しますが、これらが必要な場合は、Next.js でもこれらのオプションがサポートされています。詳細については、メタデータ APIおよびテストに関するドキュメントを参照してください。
ステップ 4: メタデータ
Next.js には、デフォルトで、メタ charsetおよびメタビューポートタグがすでに含まれているため、<head>
からそれらを安全に削除できます。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
favicon.ico
、icon.png
、robots.txt
などのメタデータファイルは、app
ディレクトリの最上位レベルに配置されている限り、アプリケーションの<head>
タグに自動的に追加されます。サポートされているすべてのファイルをapp
ディレクトリに移動した後、<link>
タグを安全に削除できます。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<head>
<title>React App</title>
<meta name="description" content="Web site created..." />
</head>
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
最後に、Next.js は メタデータ API を使用して、最後の<head>
タグを管理できます。最後のメタデータ情報をエクスポートされたmetadata
オブジェクトに移動します。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'React App',
description: 'Web site created with Next.js.',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
上記の変更により、すべてをindex.html
で宣言することから、フレームワークに組み込まれている Next.js の規約ベースのアプローチ ( メタデータ API) を使用するようになりました。このアプローチにより、ページの SEO と Web の共有性をより簡単に改善できます。
ステップ 5: スタイル
Create React App と同様に、Next.js には CSS Modules の組み込みサポートがあります。
グローバル CSS ファイルを使用している場合は、app/layout.tsx
ファイルにインポートします。
import '../index.css'
// ...
Tailwind を使用している場合は、postcss
と autoprefixer
をインストールする必要があります。
npm install postcss autoprefixer
次に、プロジェクトのルートに postcss.config.js
ファイルを作成します。
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
ステップ6:エントリポイントページの作成
Next.jsでは、page.tsx
ファイルを作成することで、アプリケーションのエントリポイントを宣言します。CRAにおけるこのファイルの最も近い対応物は、src/index.tsx
ファイルです。このステップでは、アプリケーションのエントリポイントを設定します。
app
ディレクトリに[[...slug]]
ディレクトリを作成します。
このガイドは、まずNext.jsをSPA(シングルページアプリケーション)として設定することを目的としているため、アプリケーションの可能なすべてのルートをキャッチするページエントリポイントが必要です。そのため、app
ディレクトリに新しい[[...slug]]
ディレクトリを作成します。
このディレクトリは、オプションのキャッチオールルートセグメントと呼ばれるものです。Next.jsはファイルシステムベースのルーターを使用しており、ディレクトリがルートを定義するために使用されます。この特別なディレクトリは、アプリケーションのすべてのルートが、その中にあるpage.tsx
ファイルにリダイレクトされるようにします。
app/[[...slug]]
ディレクトリ内に、以下の内容で新しいpage.tsx
ファイルを作成します。
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return '...' // We'll update this
}
このファイルはサーバーコンポーネントです。next build
を実行すると、ファイルは静的アセットにプリレンダリングされます。動的なコードは必要ありません。
このファイルはグローバルCSSをインポートし、generateStaticParams
に対して、ルートは/
にあるインデックスルートを1つだけ生成することを伝えます。
次に、クライアント側でのみ実行されるCRAアプリケーションの残りの部分を移動しましょう。
'use client'
import dynamic from 'next/dynamic'
const App = dynamic(() => import('../../App'), { ssr: false })
export function ClientOnly() {
return <App />
}
このファイルは、'use client'
ディレクティブで定義されたクライアントコンポーネントです。クライアントコンポーネントは、クライアントに送信される前に、サーバー上でHTMLにプリレンダリングされます。
クライアント側のみのアプリケーションを起動したいので、App
コンポーネント以下からのプリレンダリングを無効にするようにNext.jsを設定できます。
const App = dynamic(() => import('../../App'), { ssr: false })
次に、新しいコンポーネントを使用するようにエントリポイントページを更新します。
import { ClientOnly } from './client'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return <ClientOnly />
}
ステップ7:静的イメージインポートの更新
Next.jsは、静的イメージのインポートをCRAとはわずかに異なる方法で処理します。CRAでは、イメージファイルをインポートすると、そのパブリックURLが文字列として返されます。
import image from './img.png'
export default function App() {
return <img src={image} />
}
Next.jsでは、静的イメージのインポートはオブジェクトを返します。オブジェクトは、Next.jsの<Image>
コンポーネントで直接使用するか、オブジェクトのsrc
プロパティを既存の<img>
タグで使用できます。
<Image>
コンポーネントには、自動画像最適化という追加の利点があります。<Image>
コンポーネントは、画像サイズに基づいて、結果の<img>
のwidth
属性とheight
属性を自動的に設定します。これにより、画像のロード時のレイアウトシフトを防ぎます。ただし、アプリに、他方のサイズをauto
にスタイル設定せずに、片方のサイズのみがスタイル設定されている画像が含まれている場合、問題が発生する可能性があります。auto
にスタイル設定されていない場合、サイズはデフォルトで<img>
のサイズ属性の値になり、画像が歪んで表示される可能性があります。
<img>
タグを保持すると、アプリケーションの変更量が減り、上記の問題を防ぐことができます。その後、オプションで、ローダーを設定するか、自動画像最適化機能を備えたデフォルトのNext.jsサーバーに移行することで、画像を最適化するために<Image>
コンポーネントに移行できます。
/public
からインポートした画像の絶対インポートパスを相対インポートに変換します。
// Before
import logo from '/logo.png'
// After
import logo from '../public/logo.png'
イメージオブジェクト全体ではなく、イメージのsrc
プロパティを<img>
タグに渡します。
// Before
<img src={logo} />
// After
<img src={logo.src} />
または、ファイル名に基づいて画像アセットのパブリックURLを参照できます。たとえば、public/logo.png
はアプリケーションで/logo.png
に画像を公開しますが、これはsrc
の値になります。
警告:TypeScriptを使用している場合、
src
プロパティにアクセスするときに型エラーが発生する可能性があります。これを修正するには、include
配列のtsconfig.json
ファイルにnext-env.d.ts
を追加する必要があります。Next.jsは、ステップ9でアプリケーションを実行すると、このファイルを自動的に生成します。
ステップ8:環境変数の移行
Next.jsは、CRAと同様に、.env
環境変数をサポートしています。
主な違いは、クライアント側で環境変数を公開するために使用されるプレフィックスです。REACT_APP_
プレフィックスが付いたすべての環境変数をNEXT_PUBLIC_
に変更します。
ステップ9:package.json
のスクリプトを更新する
Next.jsに正常に移行できたかどうかをテストするために、アプリケーションを実行できるようになりました。しかし、その前に、package.json
のscripts
をNext.js関連のコマンドで更新し、.next
とnext-env.d.ts
を.gitignore
ファイルに追加する必要があります。
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "npx serve@latest ./build"
}
}
# ...
.next
next-env.d.ts
ここで、npm run dev
を実行し、https://#:3000
を開きます。アプリケーションがNext.jsで実行されているはずです。
ステップ10:クリーンアップ
これで、Create React Appに関連するアーティファクトをコードベースからクリーンアップできます。
public/index.html
を削除します。src/index.tsx
を削除します。src/react-app-env.d.ts
を削除します。reportWebVitals
の設定を削除します。- CRAの依存関係(
react-scripts
)をアンインストールします。
バンドラーの互換性
Create React AppとNext.jsはどちらも、バンドルにwebpackを使用することをデフォルトとしています。
CRAアプリケーションをNext.jsに移行する場合、移行しようとしているカスタムwebpack構成がある可能性があります。Next.jsは、カスタムwebpack構成を提供することをサポートしています。
さらに、Next.jsは、ローカル開発パフォーマンスを向上させるために、next dev --turbo
を通じてTurbopackをサポートしています。Turbopackは、互換性と段階的な導入のために、いくつかのwebpackローダーもサポートしています。
次のステップ
すべてが計画どおりに進んだ場合、シングルページアプリケーションとして機能するNext.jsアプリケーションが完成しました。ただし、まだNext.jsのメリットのほとんどを活用していませんが、メリットを最大限に享受するために段階的な変更を開始できるようになりました。次に実行する可能性のあることを次に示します。
- React RouterからNext.js App Routerに移行して、以下を取得します。
- 自動コード分割
- ストリーミングサーバーレンダリング
- Reactサーバーコンポーネント
<Image>
コンポーネントで画像を最適化next/font
でフォントを最適化<Script>
コンポーネントでサードパーティスクリプトを最適化- Next.jsルールをサポートするようにESLint構成を更新
知っておくと良いこと: 静的エクスポートを使用する場合、現在、
useParams
フックの使用はサポートされていません。
この記事は役に立ちましたか?