Next.js

Einführung

Die verfügbaren Frameworks für die Webentwicklung sind zahlreich. Die Beliebtheit eines Frameworks hängt von vielen Faktoren ab, wie z.B. der Performance, der Skalierbarkeit, der Flexibilität, der Community und der Dokumentation. Next.js verwendet React als Frontend-Bibliothek und Node.js als Backend-Server. Es wurde von der Firma Vercel entwickelt und ist ein Open-Source-Projekt unter der MIT-Lizenz.

In diesem Projekt wird Next.js verwendet, um eine Webanwendung zu erstellen, die die Funktionalität einer To-do-Liste bietet. Die Daten werden in einer Datenbank gespeichert und können über die Webanwendung hinzugefügt, bearbeitet und gelöscht werden. Dabei soll der Fokus auf der Verwendung von Next.js und der Integration von UI-Komponenten liegen.

To-do-Anwendung

Installation

Um ein neues Next.js Projekt zu erstellen, kann das create-next-app-Befehlszeilenprogramm zusammen mit node.js verwendet werden.

Der folgende Befehl erstellt ein neues Next.js Projekt:

npx create-next-app@latest

Dabei werden einige Fragen zur Konfiguration des Projekts gestellt, z.B. ob TypeScript verwendet werden soll. Für dieses Projekt werden die Standardoptionen verwendet.

  • TypeScript

  • ESLint

  • Tailwind CSS

  • Kein src-Verzeichnis

  • App Router

Es wird ein neues Verzeichnis mit dem Projektnamen erstellt, in dem sich die Dateien für das Projekt befinden. Das app-Verzeichnis enthält den Quellcode der Anwendung. In diesem Verzeichnis werden durch weitere Unterverzeichnisse die verschiedenen Seiten der Anwendung organisiert.

Routing

Next.js verwendet ein Dateisystem-basiertes Routing, bei dem die Dateistruktur die Routen der Anwendung definiert. Die Dateien im app-Verzeichnis entsprechen den Routen der Anwendung. Um z.B. eine neue Seite mit dem Namen about zu erstellen, wird ein Verzeichnis about im app-Verzeichnis erstellt. In diesem Verzeichnis wird eine Datei page.tsx erstellt, die den Inhalt der Seite als React-Komponente enthält. Die neue Seite kann später über den Pfad /about aufgerufen werden.

Erweiterte Routing-Funktionen wie dynamische, parallele und Intercept-Routen werden ebenfalls unterstützt.

Ein Beispiel für eine dynamische Route ist:

/task/[id] - eine dynamische Route, die einen Parameter id erwartet und die Seite /task/1, /task/2, usw. ermöglicht

Beispiele für parallele Routen sind:

app/@modal - eine parallele Route, die ein Dialogfenster öffnet und die Hauptseite nicht ersetzt (daher parallel zur Hauptseite angezeigt wird)

Dialogfenster

Eine weitere Möglichkeit, die Navigation in Next.js zu steuern, ist die Verwendung von Intercept-Routen, die es ermöglichen, die Navigation von einer Seite umzuleiten. Ein Anwendungsbeispiel für eine Intercept-Route ist die Anzeige eines Dialogfensters. Um das Dialogfenster in den Browserverlauf zu integrieren, wird die URL der Seite geändert, ohne die Seite neu zu laden. Der Aufruf über einen direkten Link kann dann auch auf eine anders gestaltete Seite führen, die das Dialogfenster nicht enthält.

Alternative Seite

Server-Komponenten

Next.js bietet die Möglichkeit, Server-Komponenten zu verwenden. Dabei handelt es sich um Komponenten, die auf dem Server gerendert werden und nicht im Browser. Server-Komponenten können verwendet werden, um Daten zu laden, bevor die Seite im Browser gerendert wird. Dies kann die Leistung der Anwendung verbessern, da die Daten bereits vorhanden sind, wenn die Seite im Browser angezeigt wird. Server-Komponenten können auch verwendet werden, um auf Datenbanken zuzugreifen oder andere serverseitige Aufgaben auszuführen. Effektiv kann durch eine Server-Komponente eine Frontend-Anwendung mit einem Backend-Server kombiniert werden, ohne dass ein separates Backend oder ein API-Endpunkt erforderlich ist.

Zu beachten ist jedoch, dass Server-Komponenten keine Interaktivität bieten können und daher nur für statische Inhalte geeignet sind. Für interaktive Inhalte müssen weiterhin Client-Komponenten verwendet werden.

Standardmäßig werden alle Komponenten in Next.js als Server-Komponenten behandelt, es sei denn, sie werden explizit als Client-Komponenten deklariert.

Das ist durch die Verwendung der folgenden Anweisung am Anfang der Datei möglich:

"use client";

Ebenso kann eine Server-Komponente durch die Verwendung der folgenden Anweisung explizit als Server-Komponente deklariert werden:

"use server";

UI-Komponenten

Um die Benutzeroberfläche der Anwendung zu gestalten, werden UI-Komponenten verwendet. Aus Gründen der Einfachheit und Konsistenz werden fertige Komponenten aus der Bibliothek shadcn/ui verwendet. Diese werden in das Verzeichnis app/components kopiert und in den Seiten der Anwendung verwendet.

Die Komponenten sind so konzipiert, dass sie einfach in die Anwendung integriert werden können und eine konsistente Benutzeroberfläche bieten. Sie werden in die Anwendung importiert um leicht Änderungen an der Benutzeroberfläche vornehmen zu können und ebenso nicht eine große Sammlung von Komponenten importieren zu müssen.

Datenbank

Als Datenbank wird eine PostgreSQL-Datenbank verwendet.

Zuerst sollte hier eine MongoDB-Datenbank verwendet werden, die sich durch die einfachere Dokumentbasierte Struktur besser anbietet, aber es wurde festgestellt, dass die Verwendung der ORM Bibliothek Prisma mit MongoDB nicht so einfach ist wie mit PostgreSQL.

Das liegt daran, dass Prisma bei MongoDB eine andere Datenbankstruktur benötigt als bei PostgreSQL. Bei MongoDB wird eine spezielle Konfiguration mit einem Replica Set benötigt, um Prisma zu verwenden, da MongoDB keine Transaktionen unterstützt.

Daher wurde beschlossen, PostgreSQL zu verwenden, da es einfacher ist, Prisma damit zu verwenden. Ein weiterer Vorteil von PostgreSQL ist, dass hier die von Prisma bereitgestellte Funktionalität der Datenbankmigration verwendet werden kann.

Prisma benötigt eine Konfigurationsdatei prisma/schema.prisma, in der die Datenbankverbindung und das Datenbankschema definiert werden. In diesem Fall wird eine Tabelle Task mit den Feldern id, title, description und completed definiert.

model Task {
  id          Int     @id @default(autoincrement())
  title       String  @db.VarChar(100)
  description String  @db.VarChar(1000)
  completed   Boolean
}

Prisma generiert daraus automatisch TypeScript-Dateien für die Datenbanktabellen, die in der Anwendung verwendet werden können.

Eine einfache Datenbankabfrage mit einem Filter kann wie folgt aussehen:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export async function getTasks() {
  return prisma.task.findMany({
    where: {
      completed: false
    }
  })
}

Fazit

Next.js ist ein leistungsstarkes Framework für die Webentwicklung, das die Verwendung von React und Node.js kombiniert. Es bietet viele Funktionen, die die Entwicklung von Webanwendungen erleichtern, wie z.B. Server-Komponenten, die die Leistung verbessern und die Entwicklung von Frontend- und Backend-Code vereinfachen können. Das Routing und die Navigation in Next.js sind ebenfalls sehr intuitiv zu verwenden. Es werden jedoch zugleich immer noch erweiterte Funktionen wie dynamische Routen und parallele Routen unterstützt.