Migrating from Create React App
このガイドは、既存の Create React App サイトを Next.js に移行するのに役立ちます。
Why Switch?
いくつかの理由から Create React App から Next.js に切り替えたいと思うかもしれません:
Slow initial page loading time
Create React App は純粋に Client サイドの React を使用します。Client サイドのみのアプリケーション、つまりシングルページアプリケーション(SPAs)は、初期ページの loading 時間が遅いという問題をしばしば経験します。これはいくつかの理由から起こります:
- ブラウザは、React code とあなたのアプリケーションバンドル全体がダウンロードされて実行されるのを待つ必要があり、その後で初めてあなたの code がデータをロードするための Request を送信できます。
- あなたのアプリケーションの code は、新たな機能や依存性を追加するたびに増えていきます。
No automatic code splitting
前回の loading 時間の遅さの問題は、 code の分割で多少対凇することが可能です。しかし、 code の分割を手動で行うと、パフォーマンスが悪化することがよくあります。手動でコードを分割すると、うっかりネットワークの滝のような状態を引き起こすことがあります。 Next.js はその router に組み込まれた automatic code splitting を提供します。
Network waterfalls
アプリケーションが fetch 用のデータを client サーバに直列に requests すると、パフォーマンスが低下する一般的な原因が発生します。SPA でのデータの取得における一般的なパターンは、まず placeholder を render し、その後 component がマウントされた後に fetch データをすることです。残念ながら、これはデータを fetch する子 component が、親 component が自身のデータの loading を終えるまで start できないことを意味します。
Next.js を使用すると、 client 上でのデータ取得がサポートされるだけでなく、データ取得を server にシフトするオプションも提供します。これにより、クライアント-サーバー間のウォーターフォールを排除することができます。
Fast and intentional loading states
React Suspense を通じたストリーミングの組み込みサポートを利用することで、ネットワークの滝を引き起こすことなく、どの UI の部分を最初に、そしてどの順序でロードしたいかをより意図的に制御できます。
これにより、ページのロードが速くなり、レイアウトシフト を排除することができます。
Choose the data fetching strategy
あなたのニーズに応じて、 Next.js はページと component ごとにデータ取得の strategy を選択することができます。あなたは build 時、 server 上での request 時、または client 上でデータを fetch することを決定することができます。例えば、あなたの CMS からデータを fetch し、ブログの投稿を build 時に render することができます。これにより、CDN 上で効率的にキャッシュすることができます。
Middleware
Next.js Middleware は、リクエストが完了する前にサーバー上でコードを実行することを可能にします。これは、ユーザーが認証が必要なページを訪れた際に認証されていないコンテンツのちらつきを避けるために、ユーザーをログインページにリダイレクトする場合などに特に役立ちます。また、ミドルウェアは実験や国際化にも役立ちます。
Built-in Optimizations
Images、フォント、およびサードパーティのスクリプトは、アプリケーションのパフォーマンスに大きな影響を与えることがよくあります。Next.js には、これらを自動的に最適化する組み込みコンポーネントが含まれています。
Migration Steps
このマイグレーションの目標は、できるだけ早く動作する Next.js アプリケーションを取得することで、その後、 Next.js の機能を段階的に採用することができます。まず、既存の router をマイグレーションせずに、純粋なクライアントサイドアプリケーション(SPA)として保持します。これにより、マイグレーションプロセス中に問題が発生する可能性を最小限に抑え、マージコンフリクトを減らすことができます。
Step 1: Install the Next.js Dependency
最初に行うべきことは、依存関係として next をインストールすることです:
npm install next@latest
Step 2: Create the Next.js Configuration File
プロジェクトの root にnext.config.mjsを作成します。このファイルには、あなたのNext.js 設定 optionsが保存されます。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // Outputs a Single-Page Application (SPA).
distDir: './dist', // Changes the build output directory to `./dist/`.
}
export default nextConfig
Good to know: Next.js の設定ファイルには、
.jsまたは.mjsのいずれかを使用できます。
Step 3: Update TypeScript Configuration
あなたが TypeScript を使用している場合、それを Next.js と互換性を持たせるためには、次の変更をあなたの tsconfig.json ファイルに更新する必要があります:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": ".",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"strictNullChecks": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"./dist/types/**/*.ts"
],
"exclude": ["node_modules"]
}
TypeScript の設定に関する詳細情報は、Next.js のドキュメントで見つけることができます。
Step 4: Create the Root Layout
Next.js App Router アプリケーションには、アプリケーション内のすべてのページを包括する React Server Component である root layout ファイルが必要です。このファイルは app ディレクトリの最上位に定義されます。
CRA アプリケーションにおける root layout ファイルの最も近い同等物は、index.htmlファイルで、これは<html>、<head>、そして<body>タグを含んでいます。
このステップでは、index.html ファイルを root layout ファイルに変換します:
srcディレクトリ内に新しいappディレクトリを作成します。- その
appディレクトリ内に新しいlayout.tsxファイルを作成します:
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return null
}
export default function RootLayout({ children }) {
return null
}
Good to know: Layout ファイルには
.js,.jsx,.tsxの拡張子が使用できます。
- 作成済みの
<RootLayout>component にindex.htmlファイルの内容をコピーし、body.div#rootおよびbody.scriptタグを<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>
)
}
export default function RootLayout({ children }) {
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>
)
}
Good to know: マニフェストファイル、 favicon 以外の追加アイコノグラフィー、テスト構成を無視しますが、これらが要求である場合、 Next.js はこれらの options もサポートします。
- Next.js は default でmeta charset とmeta viewport タグを含んでいるため、
<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>
)
}
export default function RootLayout({ children }) {
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>
)
}
export default function RootLayout({ children }) {
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 はMetadata 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>
)
}
export const metadata = {
title: 'React App',
description: 'Web site created with Next.js.',
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<div id="root">{children}</div>
</body>
</html>
)
}
上記の変更により、あなたはすべてをindex.htmlで宣言することから、フレームワークに組み込まれた Next.js の慣例に基づくアプローチ(Metadata API)を使用するように移行しました。このアプローチにより、ページの SEO とウェブ共有性をより簡単に向上させることができます。
Step 5: Create the Entrypoint Page
Next.js では、page.tsxファイルを作成することでアプリケーションのエントリーポイントを宣言します。このファイルの最も近い同等物は CRA 上のsrc/index.tsxファイルです。このステップでは、アプリケーションのエントリーポイントを設定します。
appディレクトリに[[...slug]]ディレクトリを作成します。
このガイドは、まず Next.js を SPA(Single Page Application)として設定することを目指しているので、アプリケーションのすべての可能な routes を catch all するためのページエントリーポイントが必要です。それを実現するために、app ディレクトリ内に新しい [[...slug]] ディレクトリを作成してください。
このディレクトリは、optional catch-all route segmentと呼ばれるものです。Next.js はファイルシステムに基づいたルーターを使用し、ディレクトリを使用してルートを定義します。この特別なディレクトリは、アプリケーションのすべてのルートが含まれるpage.tsxファイルに向けられることを保証します。
app/[[...slug]]ディレクトリ内に新しいpage.tsxファイルを以下の内容で作成します:
import '../../src/index.css'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return '...' // We'll update this
}
import '../../src/index.css'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return '...' // We'll update this
}
Good to know:
.js,.jsx, または.tsx拡張子はページファイルに使用できます。
このファイルはServer Componentです。next buildを実行すると、このファイルは静的アセットにプレレンダリングされます。動的なコードは必要ありません。
このファイルはグローバル CSS をインポートし、generateStaticParamsに対して、/でインデックスルートのみを生成することを伝えます。
さあ、CRA アプリケーションの残りを移動しましょう。これは Client だけで実行されます。
'use client'
import React from 'react'
import dynamic from 'next/dynamic'
const App = dynamic(() => import('../../src/App'), { ssr: false })
export function ClientOnly() {
return <App />
}
'use client'
import React from 'react'
import dynamic from 'next/dynamic'
const App = dynamic(() => import('../../src/App'), { ssr: false })
export function ClientOnly() {
return <App />
}
このファイルは 'use client' ディレクティブによって定義されたClient Componentです。Client Components はクライアントに送信される前にサーバー上でHTML へプレレンダリングされます。
Client 専用アプリケーションを最初から始めたい場合、App component からプレレンダリングを無効にするように Next.js を設定できます。
const App = dynamic(() => import("../../App"), { ssr: false });
Now, update your entrypoint page to use the new component:
import '../../src/index.css'
import { ClientOnly } from './client'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return <ClientOnly />
}
import '../../src/index.css'
import { ClientOnly } from './client'
export function generateStaticParams() {
return [{ slug: [''] }]
}
export default function Page() {
return <ClientOnly />
}
Step 6: Update Static Image Imports
Next.js は、CRA とは若干異なる方法で静的な image のインポートを処理します。CRA では、 image ファイルをインポートすると、その public URL が string として返されます:
import image from './img.png'
export default function App() {
return <img src={image} />
}
Next.js を使用すると、静的画像のインポートはオブジェクトを返します。このオブジェクトは Next.js の<Image>コンポーネントで直接使用することができますし、既存の<img>タグでオブジェクトのsrcプロパティを使用することもできます。
<Image>コンポーネントには自動画像最適化の追加利点があります。<Image>コンポーネントは画像の寸法に基づいて生成される<img>のwidthとheight属性を自動的に設定します。これにより、画像が読み込まれたときのレイアウトシフトを防ぐことができます。ただし、アプリに片方の寸法のみがスタイル設定されていて、もう片方がautoに設定されていない画像が含まれている場合、問題が発生する可能性があります。autoに設定されていない場合、寸法は<img>の寸法属性の値にデフォルトで設定され、画像が歪んで見える原因となることがあります。
<img>タグを保持することで、アプリケーションの変更を少なくし、上記の問題を防ぐことができます。その後、ローダーを設定することにより画像を最適化するために<Image>コンポーネントに移行することも選択できますし、自動画像最適化を持つデフォルトの Next.js サーバーに移行することもできます。
/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プロパティにアクセスするときに型エラーが発生することがあります。 これは当面無視して構いません。このガイドの最後に修正されます。
Step 7: Migrate the Environment Variables
Next.js は、CRA と同様に、.env environment variablesをサポートしています。
主な違いは、クライアント側で environment variables を公開するために使用される接頭辞です。REACT_APP_接頭辞を使用しているすべての environment variables をNEXT_PUBLIC_に変更してください。
Step 8: Update Scripts in package.json
これで Next.js への移行が成功したかどうかをテストするためにアプリケーションを実行できるようになりました。しかし、その前に、package.jsonのscriptsを Next.js 関連のコマンドに更新し、.nextとnext-env.d.tsを.gitignoreに追加する必要があります:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
# ...
.next
next-env.d.ts
dist
次にnpm run devを実行し、http://localhost:3000 を開いてください。これでアプリケーションが Next.js 上で実行されているのを見ることができるはずです。
例: Next.js に移行した CRA アプリケーションの動作例は、このリポジトリ をご覧ください。
Step 9: Clean Up
あなたは今、Create React App に関連するアーティファクトから Code ベースをクリーンアップすることができます:
- Delete
src/index.tsx - Delete
public/index.htmlを削除します - Delete
reportWebVitalsセットアップを削除 react-scriptsの CRA 依存関係をアンインストールします。
Bundler Compatibility
Create React App と Next.js の両方がバンドルのために webpack を default として使用します。
あなたが CRA アプリケーションを Next.js に移行する際、移行したいカスタムの webpack 設定があるかもしれません。Next.js は、カスタムの webpack 設定を提供することをサポートしています。
さらに、Next.js は next dev --turbo を通じて Turbopack をサポートし、ローカルの dev パフォーマンスを向上させます。さらに、Turbopack は互換性と段階的な採用のために、いくつかの webpack ローダー もサポートしています。
Next Steps
すべてが計画通りに進んだ場合、あなたは今、シングルページアプリケーションとして機能する Next.js アプリケーションを持っています。しかし、まだ Next.js の多くの利点を活用していませんが、これから段階的な変更を加えてすべての利点を享受することができます。次に行うかもしれないことはこちらです:
- React Router からNext.js App Routerに移行して以下を得る:
<Image>コンポーネントで画像を最適化するnext/fontでフォントを最適化する<Script>コンポーネントでサードパーティスクリプトを最適化する- ESLint の設定を更新して Next.js のルールをサポートする
Good to know: 静的な export を使用すると、
useParamshook は、現在サポートされていません 。