Zum Inhalt

Nächster.js Cheatsheet

Next.js - The React Framework for Production

Next.js ist ein React-Framework, das Ihnen Bausteine zur Erstellung von Webanwendungen gibt. Im Rahmen meinen wir, dass Next.js das für React benötigte Tooling und die Konfiguration übernimmt und zusätzliche Strukturen, Funktionen und Optimierungen für Ihre Anwendung bietet. < p>

generieren

Inhaltsverzeichnis

  • [Installation](LINK_0 -%20(__LINK_0___)
  • [Projektstruktur](LINK_0 -%20(Routing)(_LINK_0__)
  • Zahlungen und Layouts
  • API Routen
  • [Data Fetching](_LINK_0__ -%20(Styling)(_LINK_0__)
  • [Bildoptimierung](LINK_0 -%20(__LINK_0___)
  • [Autorisierung](LINK_0 -%20[Datenbankintegration](LINK_0 -%20[Bestellung](_LINK_0___ -%20Test
  • (__LINK_0___)
  • Beste Praktiken

Installation

Voraussetzungen

# Node.js version requirements
node --version  # Should be 16.8 or later

# Check npm version
npm --version

# Update npm if needed
npm install -g npm@latest
```_

### Erstellen Sie Next.js App
```bash
# Create new Next.js app
npx create-next-app@latest my-app

# Create with TypeScript
npx create-next-app@latest my-app --typescript

# Create with specific template
npx create-next-app@latest my-app --example with-tailwindcss

# Interactive creation
npx create-next-app@latest
```_

### Manuelle Installation
```bash
# Create project directory
mkdir my-nextjs-app
cd my-nextjs-app

# Initialize package.json
npm init -y

# Install Next.js, React, and React DOM
npm install next react react-dom

# Install TypeScript (optional)
npm install --save-dev typescript @types/react @types/node
```_

### Paket.json Scripts
```json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "export": "next export"
  }
}
```_

## Projekterstellung

### Verfügbare Vorlagen
```bash
# Official examples
npx create-next-app@latest --example api-routes
npx create-next-app@latest --example with-typescript
npx create-next-app@latest --example with-tailwindcss
npx create-next-app@latest --example with-styled-components
npx create-next-app@latest --example with-material-ui
npx create-next-app@latest --example with-redux
npx create-next-app@latest --example with-apollo
npx create-next-app@latest --example with-prisma
npx create-next-app@latest --example with-supabase
npx create-next-app@latest --example with-firebase
```_

### Entwicklungsserver
```bash
# Start development server
npm run dev

# Start on specific port
npm run dev -- -p 3001

# Start with turbo mode (faster builds)
npm run dev -- --turbo

# Start with experimental features
npm run dev -- --experimental-app
```_

### Bau und Produktion
```bash
# Build for production
npm run build

# Start production server
npm run start

# Export static site
npm run export

# Analyze bundle
npm run build -- --analyze
```_

## Projektstruktur

### App Router Structure (Next.js 13+)
```bash
my-nextjs-app/
├── app/                    # App Router (new)
│   ├── globals.css         # Global styles
│   ├── layout.tsx          # Root layout
│   ├── page.tsx           # Home page
│   ├── loading.tsx        # Loading UI
│   ├── error.tsx          # Error UI
│   ├── not-found.tsx      # 404 page
│   ├── about/
│   │   └── page.tsx       # /about route
│   ├── blog/
│   │   ├── page.tsx       # /blog route
│   │   └── [slug]/
│   │       └── page.tsx   # /blog/[slug] route
│   └── api/
│       └── users/
│           └── route.ts   # API endpoint
├── components/             # Reusable components
├── lib/                   # Utility functions
├── public/                # Static assets
├── styles/                # Additional styles
├── next.config.js         # Next.js configuration
├── package.json
└── tsconfig.json
```_

### Seiten Routerstruktur (Legacy)
```bash
my-nextjs-app/
├── pages/                 # Pages Router (legacy)
│   ├── _app.tsx          # Custom App component
│   ├── _document.tsx     # Custom Document
│   ├── index.tsx         # Home page (/)
│   ├── about.tsx         # About page (/about)
│   ├── blog/
│   │   ├── index.tsx     # Blog index (/blog)
│   │   └── [slug].tsx    # Dynamic route (/blog/[slug])
│   └── api/
│       └── users.ts      # API endpoint (/api/users)
├── components/
├── lib/
├── public/
├── styles/
├── next.config.js
└── package.json
```_

## Routing

### App Router (Next.js 13+)

#### Dateibasiertes Routing
```bash
# Route structure
app/
├── page.tsx              # / (root)
├── about/page.tsx        # /about
├── blog/
│   ├── page.tsx          # /blog
│   └── [slug]/page.tsx   # /blog/[slug]
├── shop/
│   └── [category]/
│       └── [product]/
│           └── page.tsx  # /shop/[category]/[product]
└── (dashboard)/          # Route group (doesn't affect URL)
    ├── analytics/page.tsx # /analytics
    └── settings/page.tsx  # /settings
```_

#### Dynamische Strecken
```typescript
// app/blog/[slug]/page.tsx
interface PageProps {
  params: { slug: string };
| searchParams: { [key: string]: string | string[] | undefined }; |
}

export default function BlogPost({ params, searchParams }: PageProps) {
  return <h1>Post: {params.slug}</h1>;
}

// Generate static params
export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json());

  return posts.map((post: any) => ({
    slug: post.slug,
  }));
}
```_

#### Alle Routen
```typescript
// app/shop/[...slug]/page.tsx
interface PageProps {
  params: { slug: string[] };
}

export default function Shop({ params }: PageProps) {
  // /shop/a/b/c -> params.slug = ['a', 'b', 'c']
  return <div>Shop: {params.slug.join('/')}</div>;
}
```_

### Navigation
```typescript
// Client-side navigation
import Link from 'next/link';
import { useRouter } from 'next/navigation';

function Navigation() {
  const router = useRouter();

  return (
    <nav>
      {/* Static link */}
      <Link href="/about">About</Link>

      {/* Dynamic link */}
      <Link href={`/blog/${post.slug}`}>Read Post</Link>

      {/* Programmatic navigation */}
      <button onClick={() => router.push('/dashboard')}>
        Go to Dashboard
      </button>

      {/* Replace current entry */}
      <button onClick={() => router.replace('/login')}>
        Login
      </button>

      {/* Go back */}
      <button onClick={() => router.back()}>
        Go Back
      </button>
    </nav>
  );
}
```_

### Routengruppen und Parallelstrecken
```bash
# Route groups (don't affect URL structure)
app/
├── (marketing)/
│   ├── about/page.tsx     # /about
│   └── contact/page.tsx   # /contact
├── (shop)/
│   ├── products/page.tsx  # /products
│   └── cart/page.tsx      # /cart
└── page.tsx              # /

# Parallel routes
app/
├── @analytics/
│   └── page.tsx
├── @team/
│   └── page.tsx
├── layout.tsx            # Can render both slots
└── page.tsx
```_

## Seiten und Layouts

### Root Layout
```typescript
// app/layout.tsx
import './globals.css';

export const metadata = {
  title: 'My App',
  description: 'Generated by Next.js',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <header>
          <nav>Navigation</nav>
        </header>
        <main>{children}</main>
        <footer>Footer</footer>
      </body>
    </html>
  );
}
```_

### Eingebettet Layouts
```typescript
// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="dashboard">
      <aside>
        <nav>Dashboard Navigation</nav>
      </aside>
      <main>{children}</main>
    </div>
  );
}
```_

### Seite Komponenten
```typescript
// app/page.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Welcome to Next.js!</h1>
      <p>This is the home page.</p>
    </div>
  );
}

// With metadata
export const metadata = {
  title: 'Home | My App',
  description: 'Welcome to my Next.js application',
};
```_

### Lade- und Fehlerzustände
```typescript
// app/loading.tsx
export default function Loading() {
  return (
    <div className="loading">
      <div className="spinner">Loading...</div>
    </div>
  );
}

// app/error.tsx
'use client';

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div className="error">
      <h2>Something went wrong!</h2>
      <p>{error.message}</p>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

// app/not-found.tsx
export default function NotFound() {
  return (
    <div className="not-found">
      <h2>Not Found</h2>
      <p>Could not find requested resource</p>
    </div>
  );
}
```_

## API Routen

### App Router API Routen
```typescript
// app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server';

// GET /api/users
export async function GET(request: NextRequest) {
  const searchParams = request.nextUrl.searchParams;
  const query = searchParams.get('query');

  // Fetch users from database
  const users = await fetchUsers(query);

  return NextResponse.json(users);
}

// POST /api/users
export async function POST(request: NextRequest) {
  const body = await request.json();

  // Create user
  const user = await createUser(body);

  return NextResponse.json(user, { status: 201 });
}

// PUT /api/users
export async function PUT(request: NextRequest) {
  const body = await request.json();

  // Update user
  const user = await updateUser(body);

  return NextResponse.json(user);
}

// DELETE /api/users
export async function DELETE(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const id = searchParams.get('id');

  await deleteUser(id);

  return new NextResponse(null, { status: 204 });
}
```_

### Dynamische API Routen
```typescript
// app/api/users/[id]/route.ts
interface RouteParams {
  params: { id: string };
}

export async function GET(
  request: NextRequest,
  { params }: RouteParams
) {
  const user = await fetchUser(params.id);

  if (!user) {
    return new NextResponse('User not found', { status: 404 });
  }

  return NextResponse.json(user);
}

export async function DELETE(
  request: NextRequest,
  { params }: RouteParams
) {
  await deleteUser(params.id);
  return new NextResponse(null, { status: 204 });
}
```_

### Middleware
```typescript
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Authentication check
  const token = request.cookies.get('token');

  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  // Add custom headers
  const response = NextResponse.next();
  response.headers.set('X-Custom-Header', 'value');

  return response;
}

export const config = {
  matcher: [
| '/((?!api | _next/static | _next/image | favicon.ico).*)', |
  ],
};
```_

### API Error Handling
```typescript
// lib/api-error.ts
export class ApiError extends Error {
  constructor(
    public statusCode: number,
    message: string,
    public code?: string
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

// app/api/users/route.ts
export async function GET() {
  try {
    const users = await fetchUsers();
    return NextResponse.json(users);
  } catch (error) {
    if (error instanceof ApiError) {
      return NextResponse.json(
        { error: error.message, code: error.code },
        { status: error.statusCode }
      );
    }

    return NextResponse.json(
      { error: 'Internal Server Error' },
      { status: 500 }
    );
  }
}
```_

## Datenerhebung

### Serverkomponenten (Standard)
```typescript
// app/posts/page.tsx
async function getPosts() {
  const res = await fetch('https://api.example.com/posts', {
    // Revalidate every hour
    next: { revalidate: 3600 }
  });

  if (!res.ok) {
    throw new Error('Failed to fetch posts');
  }

  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();

  return (
    <div>
      <h1>Posts</h1>
      {posts.map((post: any) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}
```_

### Kundenkomponenten
```typescript
// components/PostList.tsx
'use client';

import { useState, useEffect } from 'react';

export default function PostList() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchPosts() {
      try {
        const res = await fetch('/api/posts');
        const data = await res.json();
        setPosts(data);
      } catch (error) {
        console.error('Error fetching posts:', error);
      } finally {
        setLoading(false);
      }
    }

    fetchPosts();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {posts.map((post: any) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  );
}
```_

### Static Site Generation (SSG)
```typescript
// app/posts/[slug]/page.tsx
interface Post {
  slug: string;
  title: string;
  content: string;
}

// Generate static params at build time
export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then(res => res.json());

  return posts.map((post: Post) => ({
    slug: post.slug,
  }));
}

// Generate metadata
export async function generateMetadata({ params }: { params: { slug: string } }) {
  const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(res => res.json());

  return {
    title: post.title,
    description: post.excerpt,
  };
}

export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(res => res.json());

  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}
```_

### Inkrementelle statische Regeneration (ISR)
```typescript
// Revalidate every 60 seconds
async function getData() {
  const res = await fetch('https://api.example.com/data', {
    next: { revalidate: 60 }
  });

  return res.json();
}

// On-demand revalidation
export async function POST(request: NextRequest) {
  const secret = request.nextUrl.searchParams.get('secret');

  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ message: 'Invalid secret' }, { status: 401 });
  }

  try {
    await revalidatePath('/posts');
    return NextResponse.json({ revalidated: true });
  } catch (err) {
    return NextResponse.json({ message: 'Error revalidating' }, { status: 500 });
  }
}
```_

## Styling

### CSS Module
```css
/* styles/Home.module.css */
.container {
  padding: 0 2rem;
}

.main {
  min-height: 100vh;
  padding: 4rem 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.title {
  margin: 0;
  line-height: 1.15;
  font-size: 4rem;
  text-align: center;
}
```_

```typescript
// components/Home.tsx
import styles from '../styles/Home.module.css';

export default function Home() {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>Welcome to Next.js!</h1>
      </main>
    </div>
  );
}
```_

### Tailwind CSS
```bash
# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```_

```javascript
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      colors: {
        primary: '#3b82f6',
        secondary: '#64748b',
      },
    },
  },
  plugins: [],
};
```_

```css
/* app/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .btn-primary {
    @apply bg-primary text-white px-4 py-2 rounded hover:bg-blue-600;
  }
}
```_

### Stilierte Komponenten
```bash
# Install styled-components
npm install styled-components
npm install -D @types/styled-components
```_

```typescript
// components/Button.tsx
import styled from 'styled-components';

const StyledButton = styled.button<{ variant?: 'primary' | 'secondary' }>`
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 0.25rem;
  cursor: pointer;
  font-weight: 500;

  ${props => props.variant === 'primary' && `
    background-color: #3b82f6;
    color: white;

    &:hover {
      background-color: #2563eb;
    }
  `}

  ${props => props.variant === 'secondary' && `
    background-color: #6b7280;
    color: white;

    &:hover {
      background-color: #4b5563;
    }
  `}
`;

export default function Button({ children, variant = 'primary', ...props }) {
  return (
    <StyledButton variant={variant} {...props}>
      {children}
    </StyledButton>
  );
}
```_

### CSS-in-JS mit Emotion
```bash
# Install Emotion
npm install @emotion/react @emotion/styled
```_

```typescript
// components/Card.tsx
import styled from '@emotion/styled';
import { css } from '@emotion/react';

const Card = styled.div`
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  padding: 1rem;
  margin: 1rem 0;
`;

const cardTitle = css`
  font-size: 1.5rem;
  font-weight: bold;
  margin-bottom: 0.5rem;
  color: #1f2937;
`;

export default function ProductCard({ title, description }) {
  return (
    <Card>
      <h3 css={cardTitle}>{title}</h3>
      <p>{description}</p>
    </Card>
  );
}
```_

## Bildoptimierung

### Next.js Image Component
```typescript
import Image from 'next/image';

export default function Gallery() {
  return (
    <div>
      {/* Static image */}
      <Image
        src="/hero.jpg"
        alt="Hero image"
        width={800}
        height={600}
        priority // Load immediately
      />

      {/* Dynamic image */}
      <Image
        src={`https://api.example.com/images/${imageId}`}
        alt="Dynamic image"
        width={400}
        height={300}
        placeholder="blur"
        blurDataURL="data:image/jpeg;base64,..."
      />

      {/* Responsive image */}
      <Image
        src="/responsive.jpg"
        alt="Responsive image"
        fill
        style={{ objectFit: 'cover' }}
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
      />
    </div>
  );
}
```_

### Bildkonfiguration
```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    domains: ['example.com', 'api.example.com'],
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.example.com',
        port: '',
        pathname: '/images/**',
      },
    ],
    formats: ['image/webp', 'image/avif'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
};

module.exports = nextConfig;
```_

### Individueller Bildloader
```typescript
// lib/imageLoader.ts
export default function cloudinaryLoader({ src, width, quality }) {
| const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality |  | 'auto'}`]; |
  return `https://res.cloudinary.com/demo/image/fetch/${params.join(',')}/${src}`;
}

// Usage
<Image
  loader={cloudinaryLoader}
  src="/sample.jpg"
  alt="Sample"
  width={500}
  height={300}
/>
```_

## Leistungsoptimierung

### Bundanalyse
```bash
# Install bundle analyzer
npm install --save-dev @next/bundle-analyzer

# Configure in next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});

module.exports = withBundleAnalyzer({
  // Your Next.js config
});

# Analyze bundle
ANALYZE=true npm run build
```_

### Code Splitting
```typescript
// Dynamic imports
import dynamic from 'next/dynamic';

const DynamicComponent = dynamic(() => import('../components/HeavyComponent'), {
  loading: () => <p>Loading...</p>,
  ssr: false, // Disable server-side rendering
});

// Conditional loading
const ConditionalComponent = dynamic(
  () => import('../components/ConditionalComponent'),
  { ssr: false }
);

export default function Page() {
  const [showComponent, setShowComponent] = useState(false);

  return (
    <div>
      <button onClick={() => setShowComponent(true)}>
        Load Component
      </button>
      {showComponent && <ConditionalComponent />}
    </div>
  );
}
```_

### Lazy Loading
```typescript
import { lazy, Suspense } from 'react';

const LazyChart = lazy(() => import('../components/Chart'));

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<div>Loading chart...</div>}>
        <LazyChart />
      </Suspense>
    </div>
  );
}
```_

### Leistungsüberwachung
```typescript
// lib/analytics.ts
export function reportWebVitals(metric) {
  switch (metric.name) {
    case 'CLS':
    case 'FID':
    case 'FCP':
    case 'LCP':
    case 'TTFB':
      // Send to analytics service
      analytics.track('Web Vital', {
        name: metric.name,
        value: metric.value,
        id: metric.id,
      });
      break;
    default:
      break;
  }
}

// app/layout.tsx
import { reportWebVitals } from '../lib/analytics';

export { reportWebVitals };
```_

### Caching-Strategien
```typescript
// Static data caching
const getData = cache(async () => {
  const res = await fetch('https://api.example.com/data');
  return res.json();
});

// Request memoization
import { unstable_cache } from 'next/cache';

const getCachedData = unstable_cache(
  async (id) => {
    const data = await fetchData(id);
    return data;
  },
  ['data-cache'],
  { revalidate: 3600 } // 1 hour
);
```_

## Authentication

### NextAuth.js Setup
```bash
# Install NextAuth.js
npm install next-auth
```_

```typescript
// app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import CredentialsProvider from 'next-auth/providers/credentials';

const handler = NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    CredentialsProvider({
      name: 'credentials',
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' }
      },
      async authorize(credentials) {
        // Verify credentials
        const user = await verifyCredentials(credentials);
        return user ? { id: user.id, email: user.email } : null;
      }
    })
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.id = user.id;
      }
      return token;
    },
    async session({ session, token }) {
      session.user.id = token.id;
      return session;
    },
  },
  pages: {
    signIn: '/auth/signin',
    signUp: '/auth/signup',
  },
});

export { handler as GET, handler as POST };
```_

### Sitzungsmanagement
```typescript
// components/AuthProvider.tsx
'use client';

import { SessionProvider } from 'next-auth/react';

export default function AuthProvider({
  children,
  session,
}: {
  children: React.ReactNode;
  session: any;
}) {
  return <SessionProvider session={session}>{children}</SessionProvider>;
}

// app/layout.tsx
import AuthProvider from '../components/AuthProvider';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AuthProvider>
          {children}
        </AuthProvider>
      </body>
    </html>
  );
}
```_

### Schützte Routen
```typescript
// components/ProtectedRoute.tsx
import { useSession } from 'next-auth/react';
import { redirect } from 'next/navigation';

export default function ProtectedRoute({
  children,
}: {
  children: React.ReactNode;
}) {
  const { data: session, status } = useSession();

  if (status === 'loading') {
    return <div>Loading...</div>;
  }

  if (!session) {
    redirect('/auth/signin');
  }

  return <>{children}</>;
}

// Server-side protection
import { getServerSession } from 'next-auth';
import { redirect } from 'next/navigation';

export default async function ProtectedPage() {
  const session = await getServerSession();

  if (!session) {
    redirect('/auth/signin');
  }

  return <div>Protected content</div>;
}
```_

## Datenbankintegration

### Prisma Setup
```bash
# Install Prisma
npm install prisma @prisma/client
npx prisma init
```_

```prisma
// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Post {
  id        String   @id @default(cuid())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  String
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```_

```typescript
// lib/prisma.ts
import { PrismaClient } from '@prisma/client';

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined;
};

export const prisma = globalForPrisma.prisma ?? new PrismaClient();

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
```_

### Datenbanken
```typescript
// lib/posts.ts
import { prisma } from './prisma';

export async function getPosts() {
  return await prisma.post.findMany({
    include: {
      author: {
        select: {
          name: true,
          email: true,
        },
      },
    },
    orderBy: {
      createdAt: 'desc',
    },
  });
}

export async function createPost(data: {
  title: string;
  content: string;
  authorId: string;
}) {
  return await prisma.post.create({
    data,
    include: {
      author: true,
    },
  });
}

export async function updatePost(id: string, data: {
  title?: string;
  content?: string;
  published?: boolean;
}) {
  return await prisma.post.update({
    where: { id },
    data,
  });
}

export async function deletePost(id: string) {
  return await prisma.post.delete({
    where: { id },
  });
}
```_

### API Integration
```typescript
// app/api/posts/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getPosts, createPost } from '../../../lib/posts';

export async function GET() {
  try {
    const posts = await getPosts();
    return NextResponse.json(posts);
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch posts' },
      { status: 500 }
    );
  }
}

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const post = await createPost(body);
    return NextResponse.json(post, { status: 201 });
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to create post' },
      { status: 500 }
    );
  }
}
```_

## Bereitstellung

### Vercel Bereitstellung
```bash
# Install Vercel CLI
npm install -g vercel

# Deploy to Vercel
vercel

# Deploy to production
vercel --prod

# Set environment variables
vercel env add VARIABLE_NAME
```_

```json
// vercel.json
{
  "framework": "nextjs",
  "buildCommand": "npm run build",
  "devCommand": "npm run dev",
  "installCommand": "npm install",
  "functions": {
    "app/api/**/*.ts": {
      "maxDuration": 30
    }
  },
  "regions": ["iad1"],
  "env": {
    "DATABASE_URL": "@database-url"
  }
}
```_

### Einsatz von Docker
```dockerfile
# Dockerfile
FROM node:18-alpine AS base

# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi

# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

RUN yarn build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]
```_

### Strategische Ausfuhr
```javascript
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  trailingSlash: true,
  images: {
    unoptimized: true
  }
};

module.exports = nextConfig;
```_

```bash
# Build and export
npm run build

# Serve static files
npx serve out
```_

## Prüfung

### Jest und React Testbibliothek
```bash
# Install testing dependencies
npm install --save-dev jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom
```_

```javascript
// jest.config.js
const nextJest = require('next/jest');

const createJestConfig = nextJest({
  dir: './',
});

const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  moduleNameMapping: {
    '^@/components/(.*)$': '<rootDir>/components/$1',
    '^@/pages/(.*)$': '<rootDir>/pages/$1',
  },
  testEnvironment: 'jest-environment-jsdom',
};

module.exports = createJestConfig(customJestConfig);
```_

```javascript
// jest.setup.js
import '@testing-library/jest-dom';

Komponentenprüfung

```typescript // tests/components/Button.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import Button from '../components/Button';

describe('Button', () => { it('renders button with text', () => { render(); expect(screen.getByRole('button')).toHaveTextContent('Click me'); });

it('calls onClick when clicked', () => { const handleClick = jest.fn(); render();

fireEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);

});

it('applies correct variant styles', () => { render(); expect(screen.getByRole('button')).toHaveClass('btn-primary'); }); }); ```_

API Testing

```typescript // tests/api/users.test.ts import { createMocks } from 'node-mocks-http'; import handler from '../../pages/api/users';

describe('/api/users', () => { it('returns users list', async () => { const { req, res } = createMocks({ method: 'GET', });

await handler(req, res);

expect(res._getStatusCode()).toBe(200);
const data = JSON.parse(res._getData());
expect(Array.isArray(data)).toBe(true);

});

it('creates new user', async () => { const { req, res } = createMocks({ method: 'POST', body: { name: 'John Doe', email: 'john@example.com', }, });

await handler(req, res);

expect(res._getStatusCode()).toBe(201);
const data = JSON.parse(res._getData());
expect(data.name).toBe('John Doe');

}); }); ```_

E2E Testen mit Playwright

```bash

Install Playwright

npm install --save-dev @playwright/test npx playwright install ```_

```typescript // tests/e2e/home.spec.ts import { test, expect } from '@playwright/test';

test('homepage loads correctly', async ({ page }) => { await page.goto('/');

await expect(page).toHaveTitle(/My App/); await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible(); });

test('navigation works', async ({ page }) => { await page.goto('/');

await page.getByRole('link', { name: 'About' }).click(); await expect(page).toHaveURL('/about'); await expect(page.getByRole('heading', { name: 'About' })).toBeVisible(); }); ```_

Fehlerbehebung

Gemeinsame Themen

Hydratation Mismatch

```typescript // Fix hydration issues import { useEffect, useState } from 'react';

export default function ClientOnlyComponent() { const [hasMounted, setHasMounted] = useState(false);

useEffect(() => { setHasMounted(true); }, []);

if (!hasMounted) { return null; }

return

Client-only content
; } ```_

Speicherleaks

```typescript // Proper cleanup useEffect(() => { const subscription = api.subscribe(data => { setData(data); });

return () => { subscription.unsubscribe(); }; }, []); ```_

Fehler erstellen

```bash

Clear Next.js cache

rm -rf .next

Clear node_modules

rm -rf node_modules package-lock.json npm install

Check for TypeScript errors

npx tsc --noEmit ```_

Leistungsfragen

```typescript // Optimize re-renders import { memo, useMemo, useCallback } from 'react';

const ExpensiveComponent = memo(({ data, onUpdate }) => { const processedData = useMemo(() => { return data.map(item => ({ ...item, processed: true })); }, [data]);

const handleUpdate = useCallback((id) => { onUpdate(id); }, [onUpdate]);

return (

{processedData.map(item => ( ))}
); }); ```_

Best Practices

Projektstruktur

```bash

Recommended structure

src/ ├── app/ # App Router pages ├── components/ # Reusable components │ ├── ui/ # Basic UI components │ └── features/ # Feature-specific components ├── lib/ # Utility functions ├── hooks/ # Custom hooks ├── types/ # TypeScript types ├── styles/ # Global styles └── tests/ # Test files ```_

Performance Best Practices

```typescript // Use Server Components by default export default async function Page() { const data = await fetchData(); return

{data.title}
; }

// Use Client Components only when needed 'use client'; export default function InteractiveComponent() { const [count, setCount] = useState(0); return ; }

// Optimize images Hero ```_

SEO Best Practices

```typescript // Metadata API export const metadata = { title: 'My Page', description: 'Page description', keywords: ['next.js', 'react', 'javascript'], authors: [{ name: 'John Doe' }], openGraph: { title: 'My Page', description: 'Page description', images: ['/og-image.jpg'], }, twitter: { card: 'summary_large_image', title: 'My Page', description: 'Page description', images: ['/twitter-image.jpg'], }, };

// Dynamic metadata export async function generateMetadata({ params }) { const post = await fetchPost(params.id);

return { title: post.title, description: post.excerpt, }; } ```_

Sicherheit Best Practices

```typescript // Environment variables const apiKey = process.env.API_KEY; // Server-side only const publicApiUrl = process.env.NEXT_PUBLIC_API_URL; // Client-side accessible

// Content Security Policy const securityHeaders = [ { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline';" } ];

// next.config.js module.exports = { async headers() { return [ { source: '/(.*)', headers: securityHeaders, }, ]; }, }; ```_

--

Zusammenfassung

Next.js ist ein leistungsstarkes React-Framework, das eine komplette Lösung für den Aufbau moderner Webanwendungen bietet. Zu den wichtigsten Merkmalen gehören:

  • App Router: Neues Routing-System mit Layouts, Ladezuständen und Fehlergrenzen
  • Server Komponenten: Render-Komponenten auf dem Server für bessere Leistung
  • *API Routen: Eingebaute API-Endpunkte mit Full-Stack-Funktionen
  • *Bildoptimierung: Automatische Bildoptimierung und Lazy-Beladung
  • Performance: Eingebaute Optimierungen für Core Web Vitals
  • ** Bereitstellung**: Nahtlose Bereitstellung zu Vercel und anderen Plattformen

Für optimale Ergebnisse nutzen Sie Server Komponenten standardmäßig, verwenden Sie Client Components sparsam, implementieren Sie richtige Cache-Strategien und folgen Sie Next.js-Konventionen für Routing und Daten-Fetching.

<= <= <= <================================================================================= Funktion copyToClipboard() {\cHFFFF} const commands = document.querySelectorAll('code'); alle Befehle = ''; Befehle. Für jede(cmd) => alle Befehle += cmd.textContent + '\n'); navigator.clipboard.writeText (allCommands); Alarm ('Alle Befehle, die in die Zwischenablage kopiert werden!'); }

Funktion generierenPDF() { Fenster.print(); }