Files
it-know-how/vue/Nuxt Introduction.md
2026-10-28 08:39:04 +01:00

1156 lines
32 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nuxt – Einführung für Web-Development-Einsteiger
Nuxt ist ein Framework auf Basis von Vue. Es hilft dabei, vollständige Webanwendungen zu bauen, die schnell, suchmaschinenfreundlich und gut strukturiert sind.
Vue stellt vor allem die Bausteine für Benutzeroberflächen bereit. Nuxt ergänzt darum wichtige Konzepte für eine komplette Anwendung: Routing, Server-Side Rendering, Datenabrufe, Layouts, Middleware, Server-Endpunkte und Deployment.
> **Kurz gesagt:** Vue ist der Werkzeugkasten für die Benutzeroberfläche. Nuxt ist ein Anwendungs-Framework, das daraus eine strukturierte Webanwendung macht.
---
## Inhaltsverzeichnis
1. [Voraussetzungen](#voraussetzungen)
2. [Was ist Nuxt?](#was-ist-nuxt)
3. [Wie fügt sich Nuxt in den Web-Stack ein?](#wie-fügt-sich-nuxt-in-den-web-stack-ein)
4. [Wofür benutzt man Nuxt?](#wofür-benutzt-man-nuxt)
5. [Das wichtigste Konzept: Rendering](#das-wichtigste-konzept-rendering)
6. [Ein erstes Nuxt-Projekt](#ein-erstes-nuxt-projekt)
7. [Die Projektstruktur](#die-projektstruktur)
8. [Zentrale Nuxt-Konzepte](#zentrale-nuxt-konzepte)
9. [Praxisbeispiel: Produktseite mit API-Aufruf](#praxisbeispiel-produktseite-mit-api-aufruf)
10. [Praxisbeispiel: Eine eigene Server-API](#praxisbeispiel-eine-eigene-server-api)
11. [SEO und Meta-Informationen](#seo-und-meta-informationen)
12. [Authentifizierung und geschützte Seiten](#authentifizierung-und-geschützte-seiten)
13. [Typischer Technologie-Stack](#typischer-technologie-stack)
14. [Abgrenzung zu verwandten Technologien](#abgrenzung-zu-verwandten-technologien)
15. [Welche Probleme löst Nuxt?](#welche-probleme-löst-nuxt)
16. [Herausforderungen und typische Fehler](#herausforderungen-und-typische-fehler)
17. [Deployment und Betrieb](#deployment-und-betrieb)
18. [Wann ist Nuxt eine gute Wahl?](#wann-ist-nuxt-eine-gute-wahl)
19. [Zusammenfassung](#zusammenfassung)
---
## Voraussetzungen
Für Nuxt sind folgende Grundlagen hilfreich:
- HTML und CSS
- JavaScript-Grundlagen
- TypeScript-Grundlagen, zumindest zum Lesen von Code
- Vue-Komponenten und Reaktivität
- grundlegendes Verständnis von HTTP und APIs
Für Vue-Grundlagen siehe [[00-Vue Tutorial]]. Einen größeren Überblick über TypeScript gibt [[TYPESCRIPT_INTRO]]. Der vorhandene [[README - Vue Learning Path]] beschreibt eine sinnvolle Reihenfolge zum Lernen von Vue.
Man muss nicht bereits professionell mit Vue arbeiten. Es hilft aber, die Grundidee einer Vue-Komponente zu kennen:
```vue
<script setup lang="ts">
import { ref } from 'vue'
const message = ref('Hallo Vue!')
</script>
<template>
<h1>{{ message }}</h1>
</template>
```
Nuxt verwendet diese Vue-Komponenten weiter. Es nimmt einem zusätzlich viele Entscheidungen rund um die Gesamtstruktur der Anwendung ab.
---
## Was ist Nuxt?
Nuxt ist ein **Meta-Framework für Vue**. Ein Meta-Framework baut auf einem anderen Framework oder einer Bibliothek auf und ergänzt Funktionen für vollständige Anwendungen.
Bei Nuxt sind die wichtigsten Bestandteile:
| Bestandteil | Aufgabe |
|---|---|
| **Vue** | Komponenten, Templates und reaktive Benutzeroberflächen |
| **Nuxt** | Anwendungsstruktur, Routing, Rendering, Datenabrufe und Konventionen |
| **Vite** | Entwicklungsserver und Build-Werkzeuge |
| **Nitro** | Server-Engine für Server-Side Rendering und Server-Endpunkte |
| **TypeScript** | Statische Typprüfung und bessere IDE-Unterstützung |
Ein Nuxt-Projekt kann eine reine Website sein, aber auch eine interaktive Webanwendung mit eigenem Server-Code.
### Vue allein und Nuxt im Vergleich
Mit Vue allein baut man eine Benutzeroberfläche. Für eine komplette Anwendung muss man weitere Entscheidungen selbst treffen:
- Welches Routing wird verwendet?
- Wie werden Seiten geladen?
- Wie werden Daten vom Server abgerufen?
- Wie funktioniert Server-Side Rendering?
- Wie werden Layouts und Authentifizierung organisiert?
- Wo liegen Backend-Endpunkte?
- Wie wird die Anwendung produziert und deployed?
Nuxt liefert für diese Fragen etablierte Lösungen und eine erwartete Projektstruktur.
Das bedeutet nicht, dass Nuxt Vue ersetzt. Nuxt **verwendet Vue** und erweitert es.
---
## Wie fügt sich Nuxt in den Web-Stack ein?
Eine Webanwendung besteht meistens aus mehreren Schichten:
```text
Benutzer
↓
Browser
├── HTML
├── CSS
└── JavaScript / Vue
↓
Nuxt-Anwendung
├── Vue-Komponenten
├── Routing
├── Rendering
├── Datenabrufe
└── Server-Routen mit Nitro
↓
Backend-API / Datenbank / externer Dienst
```
### Der Ablauf einer Anfrage
Bei einer serverseitig gerenderten Seite kann der Ablauf vereinfacht so aussehen:
1. Ein Benutzer ruft `/products/42` im Browser auf.
2. Der Webserver oder eine Plattform leitet die Anfrage an Nuxt weiter.
3. Nuxt erkennt anhand des Dateinamens die passende Seite.
4. Nuxt ruft eventuell Produktdaten von einer API ab.
5. Nuxt rendert daraus HTML.
6. Der Browser zeigt dieses HTML sofort an.
7. Das JavaScript von Vue wird geladen.
8. Vue übernimmt die Seite und macht sie interaktiv. Dieser Vorgang heißt **Hydration**.
Bei einer rein clientseitig gerenderten Anwendung würde der Server zunächst ein fast leeres HTML-Dokument liefern. Erst JavaScript baut anschließend den sichtbaren Inhalt auf.
---
## Wofür benutzt man Nuxt?
Nuxt ist besonders interessant, wenn eine Anwendung mehr als eine kleine einzelne Vue-Komponente benötigt.
### Typische Use Cases
#### 1. Unternehmenswebsites
Beispiele:
- Startseite
- Leistungsübersicht
- Team- und Kontaktseiten
- mehrsprachige Inhalte
- SEO-relevante Landingpages
Server-Side Rendering oder statische Generierung sorgt dafür, dass Inhalte bereits im ausgelieferten HTML vorhanden sind.
#### 2. Blogs und Content-Websites
Nuxt kann Inhalte aus verschiedenen Quellen darstellen:
- Markdown-Dateien
- Headless CMS
- REST-API
- GraphQL-API
- Datenbank
Die Seiten können statisch vorgebaut oder bei jeder Anfrage serverseitig erzeugt werden.
#### 3. E-Commerce
Typische Seiten sind:
- Produktübersicht
- Produktdetailseite
- Suche und Filter
- Warenkorb
- Checkout
- Benutzerkonto
Produktseiten profitieren von SEO und schnellem initialem Laden. Interaktive Teile wie Filter oder Warenkorb funktionieren anschließend wie eine normale Vue-Anwendung.
#### 4. Dashboards und interne Anwendungen
Beispiele:
- Monitoring-Dashboard
- Verwaltungsoberfläche
- Reporting-Anwendung
- internes CRM
- Projekt- oder Aufgabenverwaltung
Für rein interne Anwendungen ist SEO oft weniger wichtig. Nuxt kann trotzdem nützlich sein, weil Routing, Layouts, Middleware und Datenabrufe gut strukturiert werden.
#### 5. Hybride Webanwendungen
Eine Anwendung kann unterschiedliche Seiten unterschiedlich behandeln:
- öffentliche Startseite: statisch generiert
- Blog: statisch generiert oder gecacht
- Produktseiten: serverseitig gerendert
- eingeloggtes Dashboard: clientseitig und interaktiv
- API-Endpunkte: serverseitig
Diese Mischung ist eine der größten Stärken von Nuxt.
---
## Das wichtigste Konzept: Rendering
Rendering bedeutet: Aus Daten und Komponenten wird HTML erzeugt.
### Client-Side Rendering (CSR)
Bei Client-Side Rendering liefert der Server zunächst eine JavaScript-Anwendung aus.
```text
Server → HTML-Grundgerüst + JavaScript
Browser → JavaScript startet
Browser → Inhalt wird erzeugt
```
**Vorteile:**
- sehr interaktive Anwendungen
- einfache mentale Struktur für reine Frontends
- Navigation kann nach dem ersten Laden schnell sein
**Nachteile:**
- initialer Inhalt erscheint eventuell später
- SEO kann schwieriger sein
- ohne JavaScript ist wenig Inhalt vorhanden
### Server-Side Rendering (SSR)
Bei SSR rendert der Server eine Seite pro Anfrage oder aus einem Cache.
```text
Server → Daten laden und HTML rendern
Browser → fertiges HTML anzeigen
Browser → Vue hydratisiert die Seite
```
**Vorteile:**
- schneller sichtbarer Inhalt
- gute Grundlage für SEO
- wichtige Inhalte sind bereits im HTML enthalten
**Nachteile:**
- Server muss Rendering leisten
- Server- und Browser-Code müssen sauber getrennt werden
- Hydration kann zusätzliche Fehlerquellen erzeugen
### Static Site Generation (SSG)
Bei SSG werden Seiten beim Build erzeugt und als statische Dateien ausgeliefert.
```text
Build-Zeit → Seiten erzeugen
Anfrage → fertige HTML-Datei ausliefern
```
Das passt gut zu:
- Dokumentationen
- Blogs
- Marketing-Websites
- Seiten mit seltenen Änderungen
### Hybrid Rendering
Nuxt kann verschiedene Rendering-Strategien innerhalb eines Projekts kombinieren. Das ist oft praktischer als eine Entscheidung für die gesamte Anwendung.
Beispiel:
```text
/ → statisch oder gecacht
/blog/** → statisch
/products/** → serverseitig gerendert
/account/** → geschützte interaktive Anwendung
/api/** → Server-Endpunkte
```
Die konkrete Konfiguration hängt von Nuxt-Version, Deployment-Ziel und Anwendung ab. Wichtig ist zunächst das Prinzip: **Nicht jede Route muss gleich behandelt werden.**
---
## Ein erstes Nuxt-Projekt
Ein neues Projekt kann mit dem Nuxt-Scaffolding angelegt werden:
```bash
npm create nuxt@latest my-nuxt-app
cd my-nuxt-app
npm install
npm run dev -- -o
```
Der Entwicklungsserver ist danach normalerweise unter `http://localhost:3000` erreichbar.
### Produktions-Build
```bash
npm run build
npm run preview
```
Ein Produktions-Build erzeugt eine optimierte Version der Anwendung. Das Ergebnis kann je nach Zielplattform als Node-Anwendung, serverlos oder statisch betrieben werden.
### Eine minimale Seite
```vue
<!-- pages/index.vue -->
<template>
<main>
<h1>Meine erste Nuxt-Seite</h1>
<p>Diese Seite wird über das dateibasierte Routing gefunden.</p>
</main>
</template>
```
Die Datei `pages/index.vue` entspricht der Route `/`.
---
## Die Projektstruktur
Eine typische Nuxt-Anwendung sieht ungefähr so aus:
```text
my-nuxt-app/
├── app.vue
├── nuxt.config.ts
├── package.json
├── pages/
│ ├── index.vue
│ ├── about.vue
│ └── products/
│ └── [id].vue
├── components/
│ ├── AppHeader.vue
│ └── ProductCard.vue
├── composables/
│ └── useProducts.ts
├── layouts/
│ └── default.vue
├── middleware/
│ └── auth.ts
├── plugins/
├── server/
│ └── api/
│ └── products.get.ts
├── public/
├── assets/
└── types/
```
### Wichtige Verzeichnisse und Dateien
| Pfad | Zweck |
|---|---|
| `app.vue` | globaler Einstiegspunkt der Anwendung |
| `pages/` | Seiten und automatisch erzeugte Routen |
| `components/` | wiederverwendbare Vue-Komponenten |
| `composables/` | wiederverwendbare Vue-Logik |
| `layouts/` | gemeinsame Seitenrahmen |
| `middleware/` | Logik vor dem Aufruf einer Route |
| `plugins/` | Erweiterungen, die beim Start registriert werden |
| `server/api/` | eigene API-Endpunkte |
| `public/` | Dateien mit unverändert erreichbaren URLs |
| `assets/` | zu verarbeitende Assets wie Stylesheets |
| `nuxt.config.ts` | Konfiguration von Nuxt |
| `package.json` | Abhängigkeiten und Skripte |
### Dateibasiertes Routing
Der Dateiname bestimmt die URL:
```text
pages/index.vue → /
pages/about.vue → /about
pages/products/index.vue → /products
pages/products/[id].vue → /products/:id
```
Ein dynamisches Segment wird in eckigen Klammern geschrieben:
```vue
<!-- pages/products/[id].vue -->
<script setup lang="ts">
const route = useRoute()
const productId = route.params.id
</script>
<template>
<h1>Produkt {{ productId }}</h1>
</template>
```
Nuxt verwendet dafür Vue Router, konfiguriert aber die üblichen Fälle automatisch.
---
## Zentrale Nuxt-Konzepte
### Komponenten
Komponenten in `components/` können in der Regel automatisch verwendet werden:
```vue
<!-- components/ProductCard.vue -->
<script setup lang="ts">
defineProps<{
name: string
price: number
}>()
</script>
<template>
<article>
<h2>{{ name }}</h2>
<p>{{ price.toFixed(2) }} €</p>
</article>
</template>
```
Verwendung:
```vue
<template>
<ProductCard name="Tastatur" :price="79.90" />
</template>
```
Die automatische Registrierung reduziert Import-Code. Bei großen Projekten sollte man trotzdem sinnvolle Namen und klare Verzeichnisstrukturen verwenden.
### Layouts
Ein Layout enthält wiederkehrende Struktur, zum Beispiel Navigation und Footer:
```vue
<!-- layouts/default.vue -->
<template>
<div>
<header>
<NuxtLink to="/">Shop</NuxtLink>
<NuxtLink to="/products">Produkte</NuxtLink>
</header>
<main>
<slot />
</main>
<footer>© 2026 Mein Shop</footer>
</div>
</template>
```
Eine Seite kann ein bestimmtes Layout verwenden:
```vue
<script setup lang="ts">
definePageMeta({
layout: 'admin',
})
</script>
```
### Navigation
Für interne Links wird normalerweise `NuxtLink` verwendet:
```vue
<NuxtLink to="/about">Über uns</NuxtLink>
```
Bei der Navigation kann Nuxt Seiten vorladen oder clientseitig wechseln, ohne das gesamte Dokument neu zu laden.
### Composables
Ein Composable kapselt wiederverwendbare Logik:
```ts
// composables/useCounter.ts
export function useCounter() {
const count = ref(0)
function increment() {
count.value += 1
}
return {
count,
increment,
}
}
```
Verwendung:
```vue
<script setup lang="ts">
const { count, increment } = useCounter()
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
```
Composables sind vergleichbar mit wiederverwendbaren Hilfsobjekten oder Funktionen. Sie helfen, Seiten schlank zu halten.
### `useFetch` und `$fetch`
Nuxt bietet Hilfen für API-Aufrufe.
```vue
<script setup lang="ts">
const { data, pending, error } = await useFetch('/api/products')
</script>
```
`useFetch` ist besonders für Daten geeignet, die Teil des initialen Seitenaufbaus sind. Nuxt kann den Abruf bei SSR berücksichtigen und die Daten an den Browser weitergeben.
`$fetch` wird häufig für einzelne Aktionen verwendet:
```ts
async function deleteProduct(id: string) {
await $fetch(`/api/products/${id}`, {
method: 'DELETE',
})
}
```
Als grobe Orientierung:
| Werkzeug | Typischer Zweck |
|---|---|
| `useFetch` | Daten für eine Seite laden, inklusive Lade- und Fehlerzustand |
| `useAsyncData` | komplexere oder individuellere asynchrone Datenlogik |
| `$fetch` | einzelne Requests, Formulare und Benutzeraktionen |
### Middleware
Middleware kann vor dem Anzeigen einer Seite ausgeführt werden:
```ts
// middleware/auth.ts
export default defineNuxtRouteMiddleware(() => {
const user = useCurrentUser()
if (!user.value) {
return navigateTo('/login')
}
})
```
Eine Seite kann diese Middleware aktivieren:
```vue
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
})
</script>
```
Wichtig: Client-seitige Middleware allein schützt keine geheimen Daten. Die Berechtigung muss zusätzlich auf dem Server oder in der Backend-API geprüft werden.
### Runtime-Konfiguration
Konfigurationswerte gehören nicht hartcodiert in Komponenten:
```ts
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '',
public: {
apiBase: '/api',
},
},
})
```
Verwendung:
```ts
const config = useRuntimeConfig()
// Darf im Browser verwendet werden:
console.log(config.public.apiBase)
// Nur serverseitig verfügbar:
console.log(config.apiSecret)
```
Ein Secret darf nicht unter `public` abgelegt werden. Alles unter `runtimeConfig.public` kann grundsätzlich im Browser landen.
---
## Praxisbeispiel: Produktseite mit API-Aufruf
Angenommen, eine Produktdetailseite soll Daten laden und verschiedene Zustände anzeigen.
### Dynamische Seite
```vue
<!-- pages/products/[id].vue -->
<script setup lang="ts">
type Product = {
id: string
name: string
description: string
price: number
}
const route = useRoute()
const { data: product, pending, error } = await useFetch<Product>(
`/api/products/${route.params.id}`,
)
</script>
<template>
<main>
<p v-if="pending">Produkt wird geladen …</p>
<p v-else-if="error">
Das Produkt konnte nicht geladen werden.
</p>
<article v-else-if="product">
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
<strong>{{ product.price.toFixed(2) }} €</strong>
</article>
</main>
</template>
```
### Warum ist `useFetch` hier sinnvoll?
Bei SSR kann Nuxt den Datenabruf während des Renderns durchführen. Der Benutzer erhält dadurch direkt eine Seite mit Produktinhalt. Der Browser muss nicht erst eine leere Seite anzeigen und anschließend die Daten nachladen.
Außerdem werden `pending`, `error` und `data` als reaktive Zustände bereitgestellt.
### API-Endpunkt dazu
```ts
// server/api/products/[id].get.ts
type Product = {
id: string
name: string
description: string
price: number
}
export default defineEventHandler((event): Product => {
const id = getRouterParam(event, 'id')
return {
id: id ?? 'unknown',
name: 'Beispielprodukt',
description: 'Ein Produkt aus einer Nuxt-Server-Route.',
price: 49.90,
}
})
```
In einer echten Anwendung würde der Handler beispielsweise eine Datenbank oder ein externes Backend aufrufen. Die Beispieldaten dienen nur dazu, den Ablauf zu zeigen.
---
## Praxisbeispiel: Eine eigene Server-API
Nuxt verwendet Nitro als Server-Engine. Dateien in `server/api/` werden zu API-Endpunkten.
```ts
// server/api/hello.get.ts
export default defineEventHandler(() => {
return {
message: 'Hallo aus einer Nuxt-Server-Route',
}
})
```
Der Endpunkt ist unter `/api/hello` erreichbar.
Eine POST-Route kann den Request-Body lesen:
```ts
// server/api/contact.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody<{
name?: string
message?: string
}>(event)
if (!body.name || !body.message) {
throw createError({
statusCode: 400,
statusMessage: 'Name und Nachricht sind erforderlich.',
})
}
return {
accepted: true,
name: body.name,
}
})
```
Aufruf aus einer Komponente:
```ts
await $fetch('/api/contact', {
method: 'POST',
body: {
name: 'Ada Lovelace',
message: 'Hallo!',
},
})
```
### Ist Nuxt damit ein vollständiges Backend?
Nuxt kann serverseitige Logik bereitstellen, ist aber nicht automatisch ein Ersatz für jedes Backend. Für kleinere Anwendungen oder Backend-for-Frontend-Endpunkte ist es sehr praktisch.
Ein umfangreiches Backend mit komplexen Geschäftsregeln, vielen Integrationen und großen Datenmengen kann weiterhin als separater Dienst betrieben werden, zum Beispiel mit FastAPI, Django, Go oder einem anderen Backend-Framework.
---
## SEO und Meta-Informationen
Eine öffentlich erreichbare Seite sollte einen passenden Titel und eine Beschreibung haben:
```vue
<script setup lang="ts">
useSeoMeta({
title: 'Tastaturen – Mein Shop',
description: 'Mechanische und ergonomische Tastaturen entdecken.',
})
</script>
```
Für dynamische Seiten können die Werte aus den geladenen Daten entstehen:
```vue
<script setup lang="ts">
const { data: product } = await useFetch<Product>('/api/products/42')
useSeoMeta({
title: () => product.value ? `${product.value.name} – Mein Shop` : 'Produkt',
description: () => product.value?.description,
})
</script>
```
SSR oder SSG sorgt dafür, dass Suchmaschinen wichtige Inhalte leichter vorfinden. Das allein garantiert allerdings keine gute Platzierung. Zusätzlich sind unter anderem relevant:
- sinnvolle Inhalte
- verständliche URLs
- gute Ladezeiten
- semantisches HTML
- mobile Nutzbarkeit
- interne Verlinkung
- korrekte Canonical- und Open-Graph-Metadaten
---
## Authentifizierung und geschützte Seiten
Eine typische Anwendung unterscheidet zwischen öffentlichen und geschützten Bereichen:
```text
/ → öffentlich
/products → öffentlich
/login → öffentlich
/account → Anmeldung erforderlich
/admin → Anmeldung und Admin-Rolle erforderlich
```
Ein typischer Ablauf besteht aus mehreren Schichten:
1. Frontend zeigt Login-Formular.
2. Formular ruft eine Server-Route oder externe API auf.
3. Server erstellt eine Session oder ein Token.
4. Browser erhält beispielsweise ein sicheres HttpOnly-Cookie.
5. Route-Middleware verbessert die Benutzerführung.
6. Jeder geschützte Server-Endpunkt prüft die Session erneut.
Der wichtige Sicherheitsgrundsatz lautet:
> Frontend-Prüfungen sind Komfortfunktionen. Autorisierung muss serverseitig durchgesetzt werden.
Ein Benutzer kann JavaScript im Browser verändern oder API-Aufrufe direkt senden. Deshalb darf ein Server nicht darauf vertrauen, dass eine Nuxt-Seite eine Route korrekt versteckt.
---
## Typischer Technologie-Stack
Ein möglicher Stack für eine Nuxt-Anwendung sieht so aus:
| Schicht | Beispiel | Aufgabe |
|---|---|---|
| Sprache | TypeScript | Typen, bessere Wartbarkeit und IDE-Unterstützung |
| UI | Vue 3 | Komponenten und Reaktivität |
| Framework | Nuxt | Routing, Rendering, Konventionen und Anwendungsschicht |
| Build | Vite | Entwicklungsserver und Bundling |
| Server | Nitro | SSR und Server-Endpunkte |
| Styling | CSS, Tailwind CSS oder UI-Bibliothek | Darstellung |
| Datenzugriff | `useFetch`, `$fetch`, REST oder GraphQL | Kommunikation mit APIs |
| Backend | Nitro-Route oder separater Dienst | Geschäftslogik und Integrationen |
| Datenbank | PostgreSQL, MySQL, SQLite usw. | dauerhafte Datenhaltung |
| Authentifizierung | Session- oder OAuth-Lösung | Benutzer und Berechtigungen |
| Tests | Vitest, Playwright | Unit-, Integrations- und End-to-End-Tests |
| Betrieb | Node, Docker, Serverless oder Plattform | Auslieferung der Anwendung |
Nuxt schreibt Datenbank und Backend nicht zwingend vor. Es ist möglich, Nuxt mit einer externen API zu verbinden oder die Server-Seite teilweise innerhalb derselben Anwendung zu betreiben.
### Beispiel für einen Stack
```text
Browser
↓
Nuxt + Vue + TypeScript
↓
Nitro-Server-Routen
↓
PostgreSQL
```
Oder bei einem getrennten Backend:
```text
Browser
↓
Nuxt + Vue + TypeScript
↓
REST- oder GraphQL-API
↓
FastAPI / Django / Node / Go
↓
PostgreSQL
```
---
## Abgrenzung zu verwandten Technologien
### Nuxt und Vue
| Vue | Nuxt |
|---|---|
| UI-Framework | Meta-Framework auf Basis von Vue |
| Komponenten und Reaktivität | komplette Anwendungsstruktur |
| Routing muss ergänzt werden | dateibasiertes Routing ist integriert |
| SSR muss eingerichtet werden | SSR, SSG und Hybrid Rendering sind vorgesehen |
| freie Architektur | stärkere Konventionen |
Wenn nur eine kleine interaktive Komponente oder ein einzelnes Dashboard benötigt wird, reicht Vue möglicherweise aus. Für eine größere Website mit mehreren Seiten ist Nuxt oft bequemer.
### Nuxt und Vue mit Vite
Vue mit Vite ist ein frei zusammengestelltes Frontend-Projekt. Man entscheidet selbst über:
- Router
- Datenabrufe
- State Management
- SSR
- Projektstruktur
- Deployment
Das bietet maximale Kontrolle, führt aber auch zu mehr Architekturentscheidungen. Nuxt nimmt davon einiges ab.
### Nuxt und React
React ist eine UI-Bibliothek bzw. das Zentrum eines großen Ökosystems. Nuxt ist auf Vue spezialisiert.
Ein direkter Vergleich ist häufig:
```text
Vue + Nuxt ↔ React + Next.js
```
Beide Ansätze können SSR, SSG, Routing und Server-Code bereitstellen. Die Unterschiede liegen vor allem in:
- Syntax und Komponentenmodell
- Reaktivitätsmodell
- Ökosystem
- Team-Erfahrung
- vorhandenen Bibliotheken
### Nuxt und Angular
Angular ist ein umfassendes Frontend-Framework mit vielen festen Konzepten, beispielsweise Dependency Injection, Services und RxJS.
Nuxt/Vue wirkt oft schrittweise und komponentenorientiert. Angular kann für sehr große, stark standardisierte Enterprise-Teams passend sein; Nuxt ist häufig leichter zugänglich, insbesondere wenn Vue bereits bekannt ist.
### Nuxt und Astro
Astro ist besonders stark bei inhaltsorientierten Websites. Es liefert standardmäßig möglichst wenig JavaScript aus und kann interaktive Komponenten als sogenannte Islands nachladen.
Nuxt ist stärker, wenn die Anwendung selbst eine große interaktive Vue-Anwendung ist.
Grobe Orientierung:
```text
Content zuerst, wenig Interaktion → Astro kann gut passen
Interaktive Vue-Anwendung → Nuxt kann gut passen
```
### Nuxt und klassische Backend-Frameworks
Frameworks wie Django, FastAPI, Rails oder Spring konzentrieren sich primär auf serverseitige Geschäftslogik, APIs und Datenverarbeitung.
Nuxt konzentriert sich auf die Webanwendung und die Verbindung aus UI, Rendering und Server-Schicht. Eine Nuxt-Anwendung kann ein separates Backend konsumieren oder kleinere Server-Funktionen selbst übernehmen.
---
## Welche Probleme löst Nuxt?
### 1. Routing
Ohne Konventionen muss man Routen oft manuell registrieren. Nuxt leitet Routen aus `pages/` ab.
### 2. SEO bei dynamischen Anwendungen
SSR und SSG ermöglichen HTML mit echtem Inhalt, statt nur ein leeres JavaScript-Grundgerüst auszuliefern.
### 3. Gemeinsame Projektstruktur
Teammitglieder wissen, wo Seiten, Komponenten, Middleware und Server-Routen liegen.
### 4. Datenabrufe
`useFetch` und `useAsyncData` unterstützen typische Abläufe mit Loading-, Fehler- und SSR-Zuständen.
### 5. Wiederverwendbare Layouts
Header, Navigation und Footer müssen nicht in jede Seite kopiert werden.
### 6. Server- und Client-Integration
Server-Routen können in derselben Codebasis wie die Vue-Seiten liegen. Das ist besonders nützlich für kleine APIs oder Backend-for-Frontend-Schichten.
### 7. Code-Splitting und Build
Nuxt teilt Seiten und Abhängigkeiten für die Auslieferung auf und bringt passende Build-Werkzeuge mit.
### 8. Deployment
Nuxt kann je nach Konfiguration als Node-Anwendung, statisch oder auf serverlosen Plattformen betrieben werden.
---
## Herausforderungen und typische Fehler
### Server und Browser sind nicht dasselbe
Beim SSR läuft Code zunächst auf dem Server. Browser-APIs wie `window`, `document` oder `localStorage` existieren dort nicht.
Problematisches Beispiel:
```ts
// Wird beim SSR fehlschlagen, wenn window nicht existiert.
const width = window.innerWidth
```
Eine mögliche clientseitige Lösung:
```ts
const width = ref<number | null>(null)
onMounted(() => {
width.value = window.innerWidth
})
```
Oder man verwendet `import.meta.client`, wenn die Logik gezielt nur im Browser ausgeführt werden soll.
### Hydration-Mismatches
Der Server rendert HTML. Anschließend erwartet Vue im Browser grundsätzlich dieselbe Struktur. Wenn Server und Browser unterschiedliche Werte erzeugen, kann eine Warnung oder ein fehlerhaftes Verhalten entstehen.
Riskant ist beispielsweise ein zufälliger Wert direkt im Template:
```vue
<template>
<p>{{ Math.random() }}</p>
</template>
```
Der Server und der Browser erzeugen unterschiedliche Zahlen. Besser ist ein kontrollierter, stabiler Wert oder eine bewusst erst im Browser erzeugte Anzeige.
### Datenabrufe doppelt verstehen
Nicht jeder API-Aufruf sollte mit `useFetch` umgesetzt werden. Für initiale Seitendaten ist `useFetch` meist passend, für eine Aktion nach einem Button-Klick häufig `$fetch`.
### Secrets im Browser
Private Schlüssel und Passwörter gehören nicht in Komponenten und nicht in `runtimeConfig.public`. Browser-Code ist für den Benutzer sichtbar.
### Server-Routen sind keine automatische Geschäftslogik
Eine Datei unter `server/api/` ist zunächst nur ein Endpunkt. Validierung, Fehlerbehandlung, Berechtigungsprüfung, Logging und Datenbanktransaktionen müssen trotzdem sorgfältig implementiert werden.
### Caching und veraltete Daten
SSR, statische Generierung und Caching können zu sehr schnellen Seiten führen. Gleichzeitig muss geklärt werden:
- Wie lange darf eine Antwort gecacht werden?
- Wann muss eine Seite neu erzeugt werden?
- Wie werden Änderungen sichtbar?
- Welche Daten sind benutzerspezifisch und dürfen niemals gemeinsam gecacht werden?
Besonders bei Login-Daten und persönlichen Inhalten darf kein versehentliches Server-Caching stattfinden.
### Nuxt-Konventionen lernen
Nuxt reduziert eigenen Architekturcode, führt aber eigene Konzepte ein. Am Anfang müssen unter anderem folgende Fragen beantwortet werden:
- Wann verwende ich `useFetch`?
- Wann läuft Code auf dem Server?
- Wie funktionieren Layouts und Middleware?
- Wo gehört ein Plugin hin?
- Wann brauche ich eine Server-Route?
Diese Lernkurve ist der Preis für die produktive Struktur, die Nuxt bereitstellt.
---
## Deployment und Betrieb
Nuxt wird normalerweise zunächst gebaut:
```bash
npm run build
```
Danach wird das erzeugte Ergebnis entsprechend der Zielumgebung gestartet. Bei einem Node-Deployment ist das Prinzip typischerweise:
```bash
node .output/server/index.mjs
```
Die konkrete Bereitstellung kann beispielsweise erfolgen über:
- eigenen Linux-Server
- Docker
- Kubernetes
- Plattformen mit Node-Unterstützung
- serverlose Plattformen
- statisches Hosting bei einer vollständig statisch generierten Website
### Betriebspunkte
Für eine produktive Anwendung sollten unter anderem berücksichtigt werden:
- Umgebungsvariablen
- HTTPS
- Logging
- Monitoring
- Fehlerseiten
- Performance und Caching
- Datenbankverbindungen
- Rate Limiting bei APIs
- Sicherheitsupdates der Abhängigkeiten
- Build- und Deployment-Pipeline
Nuxt vereinfacht den Build, nimmt aber nicht die Verantwortung für einen sicheren und stabilen Betrieb ab.
---
## Wann ist Nuxt eine gute Wahl?
Nuxt ist häufig eine gute Wahl, wenn:
- Vue bereits verwendet wird oder im Team bekannt ist
- mehrere Seiten und ein echtes Routing benötigt werden
- SEO und initiale Ladezeit wichtig sind
- SSR, SSG oder hybride Strategien gebraucht werden
- Frontend und kleinere Server-Funktionen zusammengehören
- eine konventionelle, gut erkennbare Projektstruktur hilfreich ist
- eine interaktive Webanwendung entstehen soll
### Wann reicht Vue mit Vite?
Vue mit Vite kann ausreichen, wenn:
- die Anwendung nur aus einem kleinen interaktiven Bereich besteht
- SSR nicht erforderlich ist
- SEO keine Rolle spielt
- die Architektur vollständig selbst festgelegt werden soll
- bereits ein separates Frontend-Setup vorhanden ist
### Wann ist ein separates Backend sinnvoll?
Ein eigenes Backend ist oft sinnvoll, wenn:
- komplexe Geschäftslogik zentral für mehrere Clients benötigt wird
- neben der Website auch mobile Apps auf dieselbe API zugreifen
- umfangreiche Hintergrundverarbeitung erforderlich ist
- Datenbankzugriffe und Berechtigungen zentral gebündelt werden sollen
- ein vorhandenes Backend weiterverwendet wird
Nuxt kann in diesem Fall weiterhin das Frontend und gegebenenfalls eine dünne Backend-for-Frontend-Schicht bereitstellen.
---
## Zusammenfassung
Nuxt ist ein Meta-Framework für Vue. Es verbindet Vue-Komponenten mit den Funktionen, die man beim Bau einer vollständigen Webanwendung benötigt:
- dateibasiertes Routing
- Layouts und Middleware
- Server-Side Rendering
- Static Site Generation
- hybrides Rendering
- Datenabrufe
- SEO-Unterstützung
- Server-API-Routen
- Build und Deployment
Der typische Denkansatz ist:
```text
Vue → Wie baue ich die Benutzeroberfläche?
Nuxt → Wie baue und betreibe ich die gesamte Webanwendung?
Nitro → Wie läuft die Server-Seite?
Vite → Wie entwickle und baue ich das Projekt?
TypeScript→ Wie mache ich den Code sicherer und wartbarer?
```
Nuxt löst viele wiederkehrende Architekturprobleme, bringt dafür aber eigene Konzepte und eine Server-/Client-Komplexität mit. Wer Vue-Grundlagen beherrscht und versteht, wo Code ausgeführt wird, kann mit Nuxt sowohl klassische Websites als auch umfangreiche interaktive Anwendungen entwickeln.
### Empfohlener Lernweg
1. JavaScript- und TypeScript-Grundlagen lernen.
2. Vue-Komponenten, Templates und Reaktivität verstehen.
3. Eine kleine Vue-Anwendung bauen.
4. Ein Nuxt-Projekt mit `pages/` und `components/` erstellen.
5. Navigation und dynamische Routen ergänzen.
6. Daten mit `useFetch` laden.
7. Eine eigene `server/api/`-Route schreiben.
8. SSR, SSG und Hydration vergleichen.
9. Authentifizierung und serverseitige Berechtigungen ergänzen.
10. Die Anwendung bauen, deployen und beobachten.
Der wichtigste praktische Lernschritt ist, eine kleine Anwendung vollständig umzusetzen: zum Beispiel eine Produktliste mit Detailseiten, Loading- und Fehlerzuständen, einer Server-Route und einer geschützten Admin-Seite.