Lang x Lang

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 時間が遅いという問題をしばしば経験します。これはいくつかの理由から起こります:

  1. ブラウザは、React code とあなたのアプリケーションバンドル全体がダウンロードされて実行されるのを待つ必要があり、その後で初めてあなたの code がデータをロードするための Request を送信できます。
  2. あなたのアプリケーションの 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 をインストールすることです:

Terminal
npm install next@latest

Step 2: Create the Next.js Configuration File

プロジェクトの root にnext.config.mjsを作成します。このファイルには、あなたのNext.js 設定 optionsが保存されます。

next.config.mjs
/** @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 ファイルに更新する必要があります:

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 ファイルに変換します:

  1. src ディレクトリ内に新しい app ディレクトリを作成します。
  2. その app ディレクトリ内に新しい layout.tsx ファイルを作成します:
app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return null
}
app/layout.js
export default function RootLayout({ children }) {
  return null
}

Good to know: Layout ファイルには .js, .jsx, .tsx の拡張子が使用できます。

  1. 作成済みの <RootLayout> component に index.html ファイルの内容をコピーし、body.div#root および body.script タグを <div id="root">{children}</div> で置き換えます:
app/layout.tsx
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>
  )
}
app/layout.js
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 もサポートします。

  1. Next.js は default でmeta charset meta viewport タグを含んでいるため、<head>からこれらを安全に削除できます:
app/layout.tsx
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>
  )
}
app/layout.js
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>
  )
}
  1. favicon.icoicon.pngrobots.txt などのメタデータファイルは、それらが app ディレクトリの最上位に配置されている限り、自動的にアプリケーションの <head> タグに追加されます。すべてのサポートされるファイルapp ディレクトリに移動した後、その <link> タグを安全に削除できます:
app/layout.tsx
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>
  )
}
app/layout.js
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>
  )
}
  1. 最後に、Next.js はMetadata APIを使用して最後の <head> タグを管理できます。最終的なメタデータ情報をエクスポートされたmetadataオブジェクトに移動してください:
app/layout.tsx
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>
  )
}
app/layout.js
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ファイルです。このステップでは、アプリケーションのエントリーポイントを設定します。

  1. appディレクトリに[[...slug]]ディレクトリを作成します。

このガイドは、まず Next.js を SPA(Single Page Application)として設定することを目指しているので、アプリケーションのすべての可能な routes を catch all するためのページエントリーポイントが必要です。それを実現するために、app ディレクトリ内に新しい [[...slug]] ディレクトリを作成してください。

このディレクトリは、optional catch-all route segmentと呼ばれるものです。Next.js はファイルシステムに基づいたルーターを使用し、ディレクトリを使用してルートを定義します。この特別なディレクトリは、アプリケーションのすべてのルートが含まれるpage.tsxファイルに向けられることを保証します。

  1. app/[[...slug]]ディレクトリ内に新しいpage.tsxファイルを以下の内容で作成します:
app/[[...slug]]/page.tsx
import '../../src/index.css'

export function generateStaticParams() {
  return [{ slug: [''] }]
}

export default function Page() {
  return '...' // We'll update this
}
app/[[...slug]]/page.js
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 だけで実行されます。

app/[[...slug]]/client.tsx
'use client'

import React from 'react'
import dynamic from 'next/dynamic'

const App = dynamic(() => import('../../src/App'), { ssr: false })

export function ClientOnly() {
  return <App />
}
app/[[...slug]]/client.js
'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:

app/[[...slug]]/page.tsx
import '../../src/index.css'
import { ClientOnly } from './client'

export function generateStaticParams() {
  return [{ slug: [''] }]
}

export default function Page() {
  return <ClientOnly />
}
app/[[...slug]]/page.js
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 として返されます:

App.tsx
import image from './img.png'

export default function App() {
  return <img src={image} />
}

Next.js を使用すると、静的画像のインポートはオブジェクトを返します。このオブジェクトは Next.js の<Image>コンポーネントで直接使用することができますし、既存の<img>タグでオブジェクトのsrcプロパティを使用することもできます。

<Image>コンポーネントには自動画像最適化の追加利点があります。<Image>コンポーネントは画像の寸法に基づいて生成される<img>widthheight属性を自動的に設定します。これにより、画像が読み込まれたときのレイアウトシフトを防ぐことができます。ただし、アプリに片方の寸法のみがスタイル設定されていて、もう片方がautoに設定されていない画像が含まれている場合、問題が発生する可能性があります。autoに設定されていない場合、寸法は<img>の寸法属性の値にデフォルトで設定され、画像が歪んで見える原因となることがあります。

<img>タグを保持することで、アプリケーションの変更を少なくし、上記の問題を防ぐことができます。その後、ローダーを設定することにより画像を最適化するために<Image>コンポーネントに移行することも選択できますし、自動画像最適化を持つデフォルトの Next.js サーバーに移行することもできます。

  1. /publicからインポートされた画像の絶対インポートパスを相対インポートに変換します:
// Before
import logo from "/logo.png";

// After
import logo from "../public/logo.png";
  1. 画像オブジェクト全体の代わりに画像の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.jsonscriptsを Next.js 関連のコマンドに更新し、.nextnext-env.d.ts.gitignoreに追加する必要があります:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}
.gitignore
# ...
.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 の多くの利点を活用していませんが、これから段階的な変更を加えてすべての利点を享受することができます。次に行うかもしれないことはこちらです:

Good to know: 静的な export を使用すると、useParams hook は、現在サポートされていません

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use