Menu

Migration von Create React App

Diese Anleitung hilft Ihnen, eine bestehende Create React App-Website zu Next.js zu migrieren.

Warum wechseln?

Es gibt mehrere Gründe, warum Sie von Create React App zu Next.js wechseln möchten:

Langsame anfängliche Seitenladezeit

Create React App verwendet reines clientseitiges React. Clientseitige Anwendungen, auch bekannt als Single-Page-Anwendungen (SPAs), erleben oft eine langsame anfängliche Seitenladezeit. Dies geschieht aus zwei Gründen:

  1. Der Browser muss warten, bis der React-Code und das gesamte Anwendungspaket heruntergeladen und ausgeführt sind, bevor Ihre Anwendung Anfragen zum Laden von Daten senden kann.
  2. Ihr Anwendungscode wächst mit jeder neuen Funktion und Abhängigkeit, die Sie hinzufügen.

Kein automatisches Code-Splitting

Das vorherige Problem der langsamen Ladezeiten kann durch Code-Splitting etwas gemildert werden. Wenn Sie jedoch versuchen, Code-Splitting manuell durchzuführen, verschlechtern Sie die Leistung oft. Es ist leicht, unbeabsichtigt Netzwerk-Wasserfälle beim manuellen Code-Splitting einzuführen. Next.js bietet automatisches Code-Splitting, das in seinen Router integriert ist.

Netzwerk-Wasserfälle

Eine häufige Ursache für schlechte Leistung sind sequenzielle Client-Server-Anfragen zum Datenabruf. Ein gängiges Muster für Datenabruf in einer SPA ist, zunächst einen Platzhalter zu rendern und dann Daten zu laden, nachdem die Komponente gemountet wurde. Unglücklicherweise bedeutet dies, dass eine untergeordnete Komponente, die Daten abruft, erst mit dem Abruf beginnen kann, nachdem die übergeordnete Komponente ihre eigenen Daten geladen hat.

Während Next.js den Datenabruf auf dem Client unterstützt, bietet es Ihnen auch die Option, den Datenabruf auf den Server zu verlagern, was Client-Server-Wasserfälle eliminieren kann.

Schnelle und beabsichtigte Ladeustände

Mit integrierter Unterstützung für Streaming durch React Suspense können Sie gezielter entscheiden, welche Teile Ihrer Benutzeroberfläche zuerst und in welcher Reihenfolge geladen werden sollen, ohne Netzwerk-Wasserfälle zu erzeugen.

Dies ermöglicht Ihnen, Seiten zu erstellen, die schneller laden und Layout-Verschiebungen eliminieren.

Wahl der Datenabfragestrategie

Je nach Ihren Anforderungen ermöglicht Next.js, die Datenabfragestrategie auf Seiten- und Komponentenbasis zu wählen. Sie können entscheiden, ob Daten zur Bauzeit, zur Anforderungszeit auf dem Server oder auf dem Client abgerufen werden sollen. Beispielsweise können Sie Daten von Ihrem CMS abrufen und Blog-Beiträge zur Bauzeit rendern, die dann effizient auf einem CDN zwischengespeichert werden können.

Middleware

Next.js Middleware ermöglicht es Ihnen, Code auf dem Server auszuführen, bevor eine Anfrage abgeschlossen wird. Dies ist besonders nützlich, um einen kurzen Auftritt von nicht authentifizierten Inhalten zu vermeiden, wenn der Benutzer eine nur für Authentifizierte zugängliche Seite aufruft, indem der Benutzer auf eine Anmeldeseite umgeleitet wird. Die Middleware ist auch nützlich für Experimente und Internationalisierung.

Integrierte Optimierungen

Bilder, Schriften und Drittanbieter-Skripte haben oft erhebliche Auswirkungen auf die Leistung einer Anwendung. Next.js verfügt über integrierte Komponenten, die diese automatisch für Sie optimieren.

Migrationsschritte

Unser Ziel bei dieser Migration ist es, so schnell wie möglich eine funktionsfähige Next.js-Anwendung zu erhalten, sodass Sie Next.js-Funktionen schrittweise übernehmen können. Zunächst werden wir es als reine clientseitige Anwendung (SPA) belassen, ohne Ihren bestehenden Router zu migrieren. Dies hilft, die Wahrscheinlichkeit von Problemen während des Migrationsprozesses zu minimieren und Zusammenführungskonflikte zu reduzieren.

Schritt 1: Next.js-Abhängigkeit installieren

Als Erstes müssen Sie next als Abhängigkeit installieren:

Terminal
npm install next@latest

Schritt 2: Next.js-Konfigurationsdatei erstellen

Erstellen Sie eine next.config.mjs im Stammverzeichnis Ihres Projekts. Diese Datei enthält Ihre Next.js-Konfigurationsoptionen.

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export', // Gibt eine Single-Page-Anwendung (SPA) aus.
  distDir: './build', // Ändert das Build-Ausgabeverzeichnis in `./dist`.
}
 
export default nextConfig

Schritt 3: Root-Layout erstellen

Eine Next.js App Router-Anwendung muss eine Root-Layout-Datei enthalten, bei der es sich um eine React Server-Komponente handelt, die alle Seiten in Ihrer Anwendung umschließt. Diese Datei wird auf der obersten Ebene des app-Verzeichnisses definiert.

Die nächstgelegene Entsprechung zur Root-Layout-Datei in einer CRA-Anwendung ist die index.html-Datei, die Ihre <html>, <head> und <body>-Tags enthält.

In diesem Schritt konvertieren Sie Ihre index.html-Datei in eine Root-Layout-Datei:

  1. Erstellen Sie ein neues app-Verzeichnis in Ihrem src-Verzeichnis.
  2. Erstellen Sie eine neue layout.tsx-Datei in diesem app-Verzeichnis:
app/layout.tsx
TypeScript
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return '...'
}

Hinweis: .js, .jsx oder .tsx Erweiterungen können für Layout-Dateien verwendet werden.

Kopieren Sie den Inhalt Ihrer index.html-Datei in die zuvor erstellte <RootLayout>-Komponente und ersetzen Sie die body.div#root- und body.noscript-Tags durch <div id="root">{children}</div>:

app/layout.tsx
TypeScript
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>
  )
}

Hinweis: Next.js ignoriert CRA's public/manifest.json-Datei, zusätzliche Symbole (außer favicon, icon und apple-icon) und Testkonfiguration, aber wenn dies Anforderungen sind, unterstützt Next.js auch diese Optionen. Weitere Informationen finden Sie in der Metadata-API und der Dokumentation zum Testen.

Schritt 4: Metadaten

Next.js enthält standardmäßig bereits die meta charset- und meta viewport-Tags, sodass Sie diese aus Ihrem <head> sicher entfernen können:

app/layout.tsx
TypeScript
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>
  )
}

Jede Metadatendatei wie favicon.ico, icon.png, robots.txt wird automatisch zum <head>-Tag der Anwendung hinzugefügt, solange Sie diese im obersten Verzeichnis des app-Ordners platzieren. Nachdem Sie alle unterstützten Dateien in das app-Verzeichnis verschoben haben, können Sie deren <link>-Tags gefahrlos löschen:

app/layout.tsx
TypeScript
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>
  )
}

Schließlich kann Next.js Ihre restlichen <head>-Tags mit der Metadata API verwalten. Verschieben Sie Ihre abschließenden Metadateninformationen in ein exportiertes metadata-Objekt:

app/layout.tsx
TypeScript
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>
  )
}

Mit den obigen Änderungen haben Sie von der Deklaration in Ihrer index.html zu Next.js' konventionsbasiertem Ansatz gewechselt, der in das Framework integriert ist (Metadata API). Dieser Ansatz ermöglicht es Ihnen, Ihr SEO und die Web-Share-Möglichkeiten Ihrer Seiten einfacher zu verbessern.

Schritt 5: Stile

Wie Create React App verfügt Next.js über integrierte Unterstützung für CSS-Module.

Wenn Sie eine globale CSS-Datei verwenden, importieren Sie diese in Ihre app/layout.tsx-Datei:

app/layout.tsx
TypeScript
import '../index.css'
 
// ...

Wenn Sie Tailwind verwenden, müssen Sie postcss und autoprefixer installieren:

Terminal
npm install postcss autoprefixer

Erstellen Sie dann eine postcss.config.js-Datei im Stammverzeichnis Ihres Projekts:

postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

Schritt 6: Einstiegspunkt-Seite erstellen

In Next.js definieren Sie einen Einstiegspunkt für Ihre Anwendung, indem Sie eine page.tsx-Datei erstellen. Das Äquivalent dieser Datei in CRA ist Ihre src/index.tsx-Datei. In diesem Schritt richten Sie den Einstiegspunkt Ihrer Anwendung ein.

Erstellen Sie ein [[...slug]]-Verzeichnis in Ihrem app-Verzeichnis.

Da diese Anleitung darauf abzielt, Next.js zunächst als SPA (Single Page Application) einzurichten, muss Ihr Seiteneintrittspunkt alle möglichen Routen Ihrer Anwendung abfangen. Erstellen Sie dazu ein neues [[...slug]]-Verzeichnis in Ihrem app-Verzeichnis.

Dieses Verzeichnis wird als optionale Catch-All-Routensegment bezeichnet. Next.js verwendet einen dateibasierten Router, bei dem Verzeichnisse zur Routendefinition verwendet werden. Dieses spezielle Verzeichnis stellt sicher, dass alle Routen Ihrer Anwendung an die darin enthaltene page.tsx-Datei weitergeleitet werden.

Erstellen Sie eine neue page.tsx-Datei im Verzeichnis app/[[...slug]] mit folgendem Inhalt:

app/[[...slug]]/page.tsx
TypeScript
export function generateStaticParams() {
  return [{ slug: [''] }]
}
 
export default function Page() {
  return '...' // Wir werden dies aktualisieren
}

Diese Datei ist eine Server-Komponente. Wenn Sie next build ausführen, wird die Datei in ein statisches Asset vorgerendert. Sie erfordert keinen dynamischen Code.

Diese Datei importiert unser globales CSS und teilt generateStaticParams mit, dass wir nur eine Route generieren werden, die Indexroute unter /.

Nun verschieben wir den Rest unserer CRA-Anwendung, der nur clientseitig läuft.

app/[[...slug]]/client.tsx
TypeScript
'use client'
 
import dynamic from 'next/dynamic'
 
const App = dynamic(() => import('../../App'), { ssr: false })
 
export function ClientOnly() {
  return <App />
}

Diese Datei ist eine Client-Komponente, definiert durch die 'use client'-Direktive. Client-Komponenten werden weiterhin vor dem Senden an den Client zu HTML vorgerendert.

Da wir eine reine Client-Anwendung starten möchten, können wir Next.js so konfigurieren, dass das Vorrendern ab der App-Komponente deaktiviert wird.

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

Aktualisieren Sie nun Ihre Einstiegspunktseite, um die neue Komponente zu verwenden:

app/[[...slug]]/page.tsx
TypeScript
import { ClientOnly } from './client'
 
export function generateStaticParams() {
  return [{ slug: [''] }]
}
 
export default function Page() {
  return <ClientOnly />
}

Schritt 7: Statische Bildimporte aktualisieren

Next.js behandelt statische Bildimporte etwas anders als CRA. Bei CRA gibt die Importierung einer Bilddatei die öffentliche URL als Zeichenfolge zurück:

App.tsx
import image from './img.png'
 
export default function App() {
  return <img src={image} />
}

Bei Next.js geben statische Bildimporte ein Objekt zurück. Das Objekt kann dann direkt mit der Next.js <Image>-Komponente verwendet oder mit der src-Eigenschaft des Objekts mit Ihrem bestehenden <img>-Tag verwendet werden.

Die <Image> Komponente bietet zusätzliche Vorteile der automatischen Bildoptimierung. Die <Image> Komponente setzt automatisch die width- und height-Attribute des resultierenden <img> basierend auf den Abmessungen des Bildes. Dies verhindert Layout-Verschiebungen beim Laden des Bildes. Dies kann jedoch Probleme verursachen, wenn Ihre App Bilder enthält, bei denen nur eine ihrer Dimensionen gestylt wird, ohne dass die andere auf auto gestylt wird. Wenn nicht auf auto gestylt, nimmt die Dimension standardmäßig den Wert des <img>-Dimensionsattributs an, was dazu führen kann, dass das Bild verzerrt erscheint.

Das Beibehalten des <img>-Tags reduziert die Menge der Änderungen in Ihrer Anwendung und verhindert die oben genannten Probleme. Sie können später optional zur <Image>-Komponente migrieren, um von der Bildoptimierung zu profitieren, indem Sie einen Loader konfigurieren oder zum Standard-Next.js-Server wechseln, der eine automatische Bildoptimierung bietet.

Konvertieren Sie absolute Import-Pfade für Bilder, die aus /public importiert werden, in relative Imports:

// Vorher
import logo from '/logo.png'
 
// Danach
import logo from '../public/logo.png'

Übergeben Sie die Bild-src-Eigenschaft anstelle des gesamten Bildobjekts an Ihr <img>-Tag:

// Vorher
<img src={logo} />
 
// Danach
<img src={logo.src} />

Alternativ können Sie die öffentliche URL für das Bildasset basierend auf dem Dateinamen referenzieren. Beispielsweise wird public/logo.png das Bild unter /logo.png für Ihre Anwendung bereitstellen, was der src-Wert wäre.

Warnung: Bei Verwendung von TypeScript können Typfehler auftreten, wenn auf die src-Eigenschaft zugegriffen wird. Um diese zu beheben, müssen Sie next-env.d.ts zum include-Array Ihrer tsconfig.json-Datei hinzufügen. Next.js generiert diese Datei automatisch, wenn Sie Ihre Anwendung in Schritt 9 ausführen.

Schritt 8: Migrieren der Umgebungsvariablen

Next.js unterstützt .env Umgebungsvariablen ähnlich wie CRA.

Der Hauptunterschied liegt im Präfix, das verwendet wird, um Umgebungsvariablen auf der Clientseite verfügbar zu machen. Ändern Sie alle Umgebungsvariablen mit dem REACT_APP_-Präfix in NEXT_PUBLIC_.

Schritt 9: Aktualisieren der Skripte in package.json

Sie sollten Ihre Anwendung jetzt ausführen können, um zu testen, ob Sie erfolgreich zu Next.js migriert sind. Aber bevor Sie das tun, müssen Sie Ihre scripts in Ihrer package.json mit Next.js-Befehlen aktualisieren und .next und next-env.d.ts zu Ihrer .gitignore-Datei hinzufügen:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "npx serve@latest ./build"
  }
}
.gitignore
# ...
.next
next-env.d.ts

Führen Sie nun npm run dev aus und öffnen Sie http://localhost:3000. Sie sollten sehen, dass Ihre Anwendung jetzt auf Next.js läuft.

Schritt 10: Aufräumen

Sie können jetzt Ihre Codebasis von Create React App-Artefakten bereinigen:

  • Löschen Sie public/index.html
  • Löschen Sie src/index.tsx
  • Löschen Sie src/react-app-env.d.ts
  • Löschen Sie reportWebVitals-Setup
  • Deinstallieren Sie CRA-Abhängigkeiten (react-scripts)

Bundler-Kompatibilität

Create React App und Next.js verwenden standardmäßig webpack für Bundling.

Bei der Migration Ihrer CRA-Anwendung zu Next.js haben Sie möglicherweise eine benutzerdefinierte Webpack-Konfiguration, die Sie migrieren möchten. Next.js unterstützt die Bereitstellung einer benutzerdefinierten Webpack-Konfiguration.

Darüber hinaus bietet Next.js Unterstützung für Turbopack über next dev --turbopack, um die Leistung Ihrer lokalen Entwicklung zu verbessern. Turbopack unterstützt auch einige Webpack-Loader für Kompatibilität und schrittweise Einführung.

Nächste Schritte

Wenn alles nach Plan gelaufen ist, haben Sie jetzt eine funktionsfähige Next.js-Anwendung, die als Single-Page-Anwendung läuft. Sie nutzen jedoch noch nicht die meisten Vorteile von Next.js, können aber jetzt mit inkrementellen Änderungen beginnen, um alle Vorteile zu nutzen. Hier ist, was Sie als Nächstes tun könnten:

Hinweis: Der statische Export unterstützt derzeit nicht die Verwendung des useParams-Hooks.