Appearance
Kapitel 13: Erweiterte Konfiguration & Optimierung
📖 Lernziele
In diesem Kapitel lernen Sie:
- ✅
next.config.jserweitert konfigurieren - ✅ Performance-Optimierungstechniken anwenden
- ✅ Benutzerdefinierte Middleware erstellen
- ✅ Fehlerbehandlung implementieren
- ✅ Internationalisierung (i18n) einrichten
13.1 Erweiterte next.config.js Konfiguration
⚙️ Grundkonfiguration (Überblick)
javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// Bilder-Konfiguration
images: {
domains: ['example.com', 'via.placeholder.com'],
formats: ['image/webp'],
},
// Umgebungsvariablen (nicht für sensible Daten!)
env: {
CUSTOM_KEY: 'mein-wert',
},
// Webpack-Konfiguration (falls nötig)
webpack: (config, { isServer }) => {
// Hier können Sie Webpack anpassen
return config;
},
};
module.exports = nextConfig;🔄 Rewrites (Proxy)
Zweck: Anfragen an eine andere URL weiterleiten (CORS-Umgehung).
javascript
const nextConfig = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
];
},
};Verwendung:
javascript
// Anfrage an /api/users wird zu https://api.example.com/users weitergeleitet
const res = await fetch('/api/users');🔀 Redirects
Zweck: Permanente oder temporäre Weiterleitungen.
javascript
const nextConfig = {
async redirects() {
return [
{
source: '/alt',
destination: '/neu',
permanent: true, // 301 Redirect (SEO-freundlich)
},
{
source: '/temporär',
destination: '/neu',
permanent: false, // 302 Redirect
},
];
},
};📦 Bundle-Analyse
Installation:
bash
pnpm add -D @next/bundle-analyzerKonfiguration (next.config.js):
javascript
const withBundleAnalyzer = require('@next/bundle-analyzer');
const nextConfig = withBundleAnalyzer({
reactStrictMode: true,
// ... andere Konfiguration
});
module.exports = nextConfig;Verwendung:
bash
ANALYZE=true npm run build13.2 Performance-Optimierung
⚡ Code-Splitting (Automatisch)
Next.js führt automatisches Code-Splitting durch (jede Seite lädt nur ihren eigenen JavaScript-Code).
Manuelles dynamisches Importieren:
jsx
import dynamic from 'next/dynamic';
// Dynamisches Importieren (Lazy Loading)
const DynamicComponent = dynamic(() => import('@/components/HeavyComponent'), {
loading: () => <p>Lädt...</p>,
ssr: false, // Nur Client-seitig (z.B. für Chart-Bibliotheken)
});
export default function HomePage() {
return (
<div>
<h1>Startseite</h1>
<DynamicComponent />
</div>
);
}🖼️ Bildoptimierung (next/image)
Vorteile:
- ✅ Automatische WebP-Konvertierung
- ✅ Lazy Loading
- ✅ Größenanpassung
Beispiel:
jsx
import Image from 'next/image';
import logo from '@/public/logo.png';
export default function HomePage() {
return (
<div>
{/* Lokales Bild */}
<Image
src={logo}
alt="Logo"
width={200}
height={100}
priority // Für kritische Bilder (Above the Fold)
/>
{/* Remote Bild */}
<Image
src="https://example.com/bild.jpg"
alt="Remote Bild"
width={500}
height={300}
loading="lazy" // Standard (Lazy Loading)
/>
</div>
);
}next.config.js für Remote-Bilder:
javascript
const nextConfig = {
images: {
domains: ['example.com', 'via.placeholder.com'],
// Oder für alle Domains (Next.js 14+)
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
},
],
},
};🔤 Font-Optimierung (next/font)
Google Fonts:
jsx
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html lang="de" className={inter.className}>
<body>{children}</body>
</html>
);
}Lokale Fonts:
javascript
import localFont from 'next/font/local';
const myFont = localFont({
src: [
{
path: './fonts/my-font.woff2',
weight: '400',
style: 'normal',
},
{
path: './fonts/my-font-bold.woff2',
weight: '700',
style: 'normal',
},
],
variable: '--font-my-font',
});
export default function RootLayout({ children }) {
return (
<html lang="de" className={myFont.variable}>
<body>{children}</body>
</html>
);
}📦 Caching-Strategien
Fetch-Caching (Server Components):
jsx
// 1. Standard (gecacht)
const res = await fetch('https://api.example.com/data');
// 2. Kein Cache (immer aktuell)
const res = await fetch('https://api.example.com/data', { cache: 'no-store' });
// 3. Revalidierung (alle 60 Sekunden)
const res = await fetch('https://api.example.com/data', { next: { revalidate: 60 } });ISR (Incremental Static Regeneration):
jsx
// app/blog/[slug]/page.js
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(res => res.json());
return posts.map((post) => ({
slug: post.slug,
}));
}
export default async function BlogPost() {
// ISR: Alle 60 Sekunden aktualisieren
const res = await fetch('https://api.example.com/posts', { next: { revalidate: 60 } });
// ...
}13.3 Benutzerdefinierte Middleware
🎯 Was ist Middleware?
Middleware führt Code vor dem Laden einer Seite aus (z.B. für Auth-Prüfung, Weiterleitungen).
📝 Middleware erstellen
Datei: middleware.js (im Projekt-Root)
javascript
import { NextResponse } from 'next/server';
export function middleware(request) {
// Beispiel: Auth-Prüfung
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
// Weiterleitung basierend auf Sprache
const locale = request.cookies.get('locale')?.value || 'de';
if (request.nextUrl.pathname === '/') {
return NextResponse.redirect(new URL(`/${locale}`, request.url));
}
}
// Welche Routen sollen abgefangen werden?
export const config = {
matcher: ['/dashboard/:path*', '/'],
};🌐 Anwendungsfall: Sprachweiterleitung
javascript
import { NextResponse } from 'next/server';
export function middleware(request) {
// Sprache aus Header ermitteln
const acceptLanguage = request.headers.get('accept-language') || 'de';
const locale = acceptLanguage.split(',')[0].split('-')[0];
// Weiterleitung, wenn keine Sprache in der URL
if (request.nextUrl.pathname === '/') {
return NextResponse.redirect(new URL(`/${locale}`, request.url));
}
}
export const config = {
matcher: ['/'],
};13.4 Fehlerbehandlung
📝 error.js (Fehlerbehandlung pro Route)
Datei: app/error.js (oder in einem Unterordner)
jsx
'use client';
export default function Error({ error, reset }) {
return (
<div style={{ textAlign: 'center', padding: '100px' }}>
<h1>Etwas ist schiefgegangen!</h1>
<p>{error.message}</p>
<button onClick={() => reset()}>Erneut versuchen</button>
</div>
);
}📝 not-found.js (404-Seite)
Datei: app/not-found.js
jsx
import Link from 'next/link';
export default function NotFound() {
return (
<div style={{ textAlign: 'center', padding: '100px' }}>
<h1>404 - Seite nicht gefunden</h1>
<p>Die angeforderte Seite existiert nicht.</p>
<Link href="/">Zur Startseite</Link>
</div>
);
}🛠️ Globale Fehlerbehandlung (API-Routen)
Beispiel: app/api/route.js
javascript
export async function GET() {
try {
const data = await fetchData();
return Response.json(data);
} catch (error) {
console.error('API-Fehler:', error);
return Response.json(
{ error: 'Interner Serverfehler' },
{ status: 500 }
);
}
}13.5 Internationalisierung (i18n)
⚠️ Next.js 14: i18n wird durch Middleware ersetzt
In Next.js 14 (App Router) wird keine eingebaute i18n-Unterstützung mehr angeboten. Stattdessen verwendet man Middleware oder Bibliotheken wie next-intl.
🌍 Einfache Sprachunterstützung (Middleware)
middleware.js:
javascript
import { NextResponse } from 'next/server';
const locales = ['de', 'en', 'fr'];
const defaultLocale = 'de';
export function middleware(request) {
const pathname = request.nextUrl.pathname;
// Wenn die URL bereits eine Sprache enthält
const pathnameHasLocale = locales.some(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);
if (pathnameHasLocale) return NextResponse.next();
// Weiterleitung zur Standardsprache
return NextResponse.redirect(
new URL(`/${defaultLocale}${pathname}`, request.url)
);
}
export const config = {
matcher: ['/((?!_next|favicon.ico).*)'],
};Verzeichnisstruktur:
app/
├── [locale]/
│ ├── layout.js
│ ├── page.js
│ └── about/
│ └── page.jsapp/[locale]/layout.js:
jsx
export default function LocaleLayout({ children, params }) {
const { locale } = params;
return (
<html lang={locale}>
<body>
{children}
</body>
</html>
);
}📚 next-intl Bibliothek (Empfohlen)
Installation:
bash
pnpm add next-intlKonfiguration: Folgen Sie der offiziellen Dokumentation.
📝 Zusammenfassung
In diesem Kapitel haben Sie gelernt:
| Konzept | Erklärung |
|---|---|
| next.config.js | Rewrites, Redirects, Bundle-Analyse |
| Performance | Code-Splitting, Bildoptimierung, Font-Optimierung |
| Caching | Fetch-Caching, ISR |
| Middleware | Auth-Prüfung, Sprachweiterleitung |
| Fehlerbehandlung | error.js, not-found.js |
| i18n | Internationalisierung mit Middleware |
✅ Nächste Schritte
- ✅ Übung: Konfigurieren Sie
next.config.jsmit Rewrites - ✅ Übung: Implementieren Sie eine Middleware für Auth-Prüfung
- ✅ Weiter geht's: Kapitel 14 - Deployment & Live-Schaltung
🎯 Selbsttest
Frage 1: Wie konfiguriert man Rewrites in next.config.js?
Antwort anzeigen
Durch Hinzufügen der `async rewrites()` Funktion zur Konfiguration.Frage 2: Was ist der Vorteil von next/image?
Antwort anzeigen
Automatische WebP-Konvertierung, Lazy Loading und Größenanpassung.Frage 3: Wo platziert man die Middleware-Datei?
Antwort anzeigen
Im Projekt-Root (`middleware.js`).🚀 Weiter zu Kapitel 14: Deployment & Live-Schaltung
