Zum Inhalt

Nuxt.js Cheatsheet

Nuxt.js - Der intuitive Vue Framework

Nuxt.js ist ein kostenloses und Open-Source-Framework mit einer intuitiven und erweiterbaren Möglichkeit, mit Vue.js typsichere, performante und produktionsfähige Full-Stack-Webanwendungen und Websites zu erstellen. < p>

generieren

Inhaltsverzeichnis

  • [Installation](LINK_0 -%20(__LINK_0___)
  • [Projektstruktur](LINK_0 -%20(Routing)(_LINK_0__)
  • Zahlungen und Layouts
  • Komponenten
  • [Data Fetching](_LINK_0__ -%20[State%20Management](LINK_0 -%20(Styling)(_LINK_0__)
  • Plugins
  • [Module](LINK_0___ -%20[Server-Side%20Rendering](_LINK_0 -%20API%20Routen
  • [Bestellung](_LINK_0___ -%20Test
  • (__LINK_0___)
  • (__LINK_0___)
  • Beste Praktiken

Installation

Voraussetzungen

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

# Check npm version
npm --version

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

### Nuxt.js App erstellen
```bash
# Create new Nuxt.js app
npx nuxi@latest init my-app

# Navigate to project
cd my-app

# Install dependencies
npm install

# Start development server
npm run dev
```_

### Alternative Installation Methoden
```bash
# Using yarn
yarn create nuxt-app my-app

# Using pnpm
pnpm dlx nuxi@latest init my-app

# Using specific template
npx nuxi@latest init my-app --template ui
npx nuxi@latest init my-app --template content
npx nuxi@latest init my-app --template module
```_

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

# Initialize package.json
npm init -y

# Install Nuxt.js
npm install nuxt

# Install Vue dependencies
npm install vue@latest

# Add scripts to package.json
```_

### Paket.json Scripts
```json
{
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  }
}
```_

## Projekterstellung

### Starter Vorlagen
```bash
# Official templates
npx nuxi@latest init my-app --template ui          # Nuxt UI
npx nuxi@latest init my-app --template content     # Nuxt Content
npx nuxi@latest init my-app --template module      # Nuxt Module
npx nuxi@latest init my-app --template layer       # Nuxt Layer

# Community templates
npx nuxi@latest init my-app --template docus       # Documentation
npx nuxi@latest init my-app --template minimal     # Minimal setup
```_

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

# Start with specific port
npm run dev -- --port 3001

# Start with specific host
npm run dev -- --host 0.0.0.0

# Start with HTTPS
npm run dev -- --https

# Start with tunnel
npm run dev -- --tunnel
```_

### Befehle erstellen
```bash
# Build for production
npm run build

# Generate static site
npm run generate

# Preview production build
npm run preview

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

## Projektstruktur

### Nuxt 3 Struktur
```bash
my-nuxt-app/
├── .nuxt/                 # Auto-generated files
├── .output/               # Build output
├── assets/                # Uncompiled assets
├── components/            # Vue components
├── composables/           # Vue composables
├── content/               # Content files (if using @nuxt/content)
├── layouts/               # Layout components
├── middleware/            # Route middleware
├── pages/                 # File-based routing
├── plugins/               # Plugins
├── public/                # Static files
├── server/                # Server-side code
│   ├── api/              # API routes
│   └── middleware/       # Server middleware
├── stores/                # Pinia stores
├── utils/                 # Utility functions
├── app.vue               # Main app component
├── nuxt.config.ts        # Nuxt configuration
├── package.json
└── tsconfig.json
```_

### Konfigurationsdateien
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  // Basic configuration
  devtools: { enabled: true },

  // CSS framework
  css: ['~/assets/css/main.css'],

  // Modules
  modules: [
    '@nuxtjs/tailwindcss',
    '@pinia/nuxt',
    '@nuxt/content'
  ],

  // Runtime config
  runtimeConfig: {
    // Private keys (only available on server-side)
    apiSecret: '123',
    // Public keys (exposed to client-side)
    public: {
      apiBase: '/api'
    }
  },

  // App configuration
  app: {
    head: {
      title: 'My Nuxt App',
      meta: [
        { charset: 'utf-8' },
        { name: 'viewport', content: 'width=device-width, initial-scale=1' }
      ]
    }
  }
});
```_

## Routing

### Dateibasiertes Routing
```bash
# Route structure
pages/
├── index.vue             # / (root)
├── about.vue             # /about
├── blog/
│   ├── index.vue         # /blog
│   └── [slug].vue        # /blog/[slug]
├── users/
│   ├── index.vue         # /users
│   ├── [id].vue          # /users/[id]
│   └── [id]/
│       └── edit.vue      # /users/[id]/edit
└── [...slug].vue         # Catch-all route
```_

### Dynamische Strecken
```vue
<!-- pages/blog/[slug].vue -->
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
  </div>
</template>

<script setup>
// Get route parameters
const route = useRoute();
const slug = route.params.slug;

// Fetch data based on slug
const { data: post } = await $fetch(`/api/posts/${slug}`);

// Define page meta
definePageMeta({
  title: 'Blog Post',
  description: 'Read our latest blog post'
});
</script>
```_

### Eingebettete Routen
```vue
<!-- pages/users/[id].vue -->
<template>
  <div>
    <h1>User Profile</h1>
    <NuxtPage />
  </div>
</template>

<!-- pages/users/[id]/index.vue -->
<template>
  <div>
    <h2>{{ user.name }}</h2>
    <p>{{ user.email }}</p>
  </div>
</template>

<!-- pages/users/[id]/edit.vue -->
<template>
  <div>
    <h2>Edit User</h2>
    <form @submit="updateUser">
      <!-- Form fields -->
    </form>
  </div>
</template>
```_

### Navigation
```vue
<template>
  <nav>
    <!-- Static navigation -->
    <NuxtLink to="/">Home</NuxtLink>
    <NuxtLink to="/about">About</NuxtLink>

    <!-- Dynamic navigation -->
    <NuxtLink :to="`/blog/${post.slug}`">{{ post.title }}</NuxtLink>

    <!-- External links -->
    <NuxtLink to="https://nuxtjs.org" external>Nuxt.js</NuxtLink>

    <!-- Programmatic navigation -->
    <button @click="navigateTo('/dashboard')">Dashboard</button>
    <button @click="navigateTo('/login', { replace: true })">Login</button>
  </nav>
</template>

<script setup>
// Programmatic navigation
const router = useRouter();

function goToProfile() {
  router.push('/profile');
}

function goBack() {
  router.back();
}

// Navigation guards
definePageMeta({
  middleware: 'auth'
});
</script>
```_

### Route Middleware
```typescript
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const user = useAuthUser();

  if (!user.value) {
    return navigateTo('/login');
  }
});

// middleware/admin.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  // Global middleware runs on every route change
  console.log('Navigating to:', to.path);
});
```_

## Seiten und Layouts

### Default Layout
```vue
<!-- layouts/default.vue -->
<template>
  <div>
    <header>
      <nav>
        <NuxtLink to="/">Home</NuxtLink>
        <NuxtLink to="/about">About</NuxtLink>
        <NuxtLink to="/blog">Blog</NuxtLink>
      </nav>
    </header>

    <main>
      <slot />
    </main>

    <footer>
      <p>&copy; 2024 My Nuxt App</p>
    </footer>
  </div>
</template>

<style scoped>
header {
  background: #f8f9fa;
  padding: 1rem;
}

nav a {
  margin-right: 1rem;
  text-decoration: none;
}

main {
  min-height: 80vh;
  padding: 2rem;
}

footer {
  background: #343a40;
  color: white;
  text-align: center;
  padding: 1rem;
}
</style>
```_

### Benutzerdefinierte Layouts
```vue
<!-- layouts/admin.vue -->
<template>
  <div class="admin-layout">
    <aside class="sidebar">
      <nav>
        <NuxtLink to="/admin">Dashboard</NuxtLink>
        <NuxtLink to="/admin/users">Users</NuxtLink>
        <NuxtLink to="/admin/posts">Posts</NuxtLink>
      </nav>
    </aside>

    <main class="content">
      <slot />
    </main>
  </div>
</template>

<style scoped>
.admin-layout {
  display: flex;
  min-height: 100vh;
}

.sidebar {
  width: 250px;
  background: #2c3e50;
  color: white;
  padding: 1rem;
}

.content {
  flex: 1;
  padding: 2rem;
}
</style>
```_

### Layouts in Seiten verwenden
```vue
<!-- pages/admin/index.vue -->
<template>
  <div>
    <h1>Admin Dashboard</h1>
    <div class="stats">
      <div class="stat">
        <h3>Users</h3>
        <p>{{ stats.users }}</p>
      </div>
      <div class="stat">
        <h3>Posts</h3>
        <p>{{ stats.posts }}</p>
      </div>
    </div>
  </div>
</template>

<script setup>
// Use custom layout
definePageMeta({
  layout: 'admin',
  middleware: 'admin-auth'
});

// Fetch dashboard stats
const { data: stats } = await $fetch('/api/admin/stats');
</script>
```_

### Seite Meta und SEO
```vue
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.content }}</p>
  </div>
</template>

<script setup>
const route = useRoute();
const { data: post } = await $fetch(`/api/posts/${route.params.slug}`);

// Dynamic page meta
useHead({
  title: post.title,
  meta: [
    { name: 'description', content: post.excerpt },
    { name: 'keywords', content: post.tags.join(', ') },
    { property: 'og:title', content: post.title },
    { property: 'og:description', content: post.excerpt },
    { property: 'og:image', content: post.image },
    { property: 'og:url', content: `https://example.com/blog/${post.slug}` }
  ]
});

// Structured data
useJsonld({
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
  headline: post.title,
  description: post.excerpt,
  author: {
    '@type': 'Person',
    name: post.author.name
  },
  datePublished: post.publishedAt
});
</script>
```_

## Komponenten

### Autoimportierte Komponenten
```vue
<!-- components/TheHeader.vue -->
<template>
  <header class="header">
    <div class="container">
      <NuxtLink to="/" class="logo">
        <img src="/logo.png" alt="Logo" />
      </NuxtLink>

      <nav class="nav">
        <NuxtLink to="/">Home</NuxtLink>
        <NuxtLink to="/about">About</NuxtLink>
        <NuxtLink to="/blog">Blog</NuxtLink>
      </nav>
    </div>
  </header>
</template>

<script setup>
// Component is auto-imported and can be used as <TheHeader />
</script>
```_

### Eingebettete Komponenten
```vue
<!-- components/blog/PostCard.vue -->
<template>
  <article class="post-card">
    <img :src="post.image" :alt="post.title" />
    <div class="content">
      <h3>{{ post.title }}</h3>
      <p>{{ post.excerpt }}</p>
      <NuxtLink :to="`/blog/${post.slug}`" class="read-more">
        Read More
      </NuxtLink>
    </div>
  </article>
</template>

<script setup>
interface Post {
  id: string;
  title: string;
  excerpt: string;
  image: string;
  slug: string;
}

defineProps<{
  post: Post;
}>();
</script>

<!-- Usage: <BlogPostCard :post="post" /> -->
```_

### Composables
```typescript
// composables/useAuth.ts
export const useAuth = () => {
  const user = useState<User | null>('auth.user', () => null);

  const login = async (credentials: LoginCredentials) => {
    const { data } = await $fetch('/api/auth/login', {
      method: 'POST',
      body: credentials
    });

    user.value = data.user;
    await navigateTo('/dashboard');
  };

  const logout = async () => {
    await $fetch('/api/auth/logout', { method: 'POST' });
    user.value = null;
    await navigateTo('/');
  };

  const isAuthenticated = computed(() => !!user.value);

  return {
    user: readonly(user),
    login,
    logout,
    isAuthenticated
  };
};

// Usage in components
const { user, login, logout, isAuthenticated } = useAuth();
```_

### Globaler Staat mit NutzungState
```typescript
// composables/useCounter.ts
export const useCounter = () => {
  const count = useState('counter', () => 0);

  const increment = () => count.value++;
  const decrement = () => count.value--;
  const reset = () => count.value = 0;

  return {
    count: readonly(count),
    increment,
    decrement,
    reset
  };
};
```_

## Datenerhebung

### Serverseitige Datenerfassung
```vue
<template>
  <div>
    <h1>Posts</h1>
    <div v-for="post in posts" :key="post.id">
      <h2>{{ post.title }}</h2>
      <p>{{ post.excerpt }}</p>
    </div>
  </div>
</template>

<script setup>
// Fetch data on server-side
const { data: posts } = await $fetch('/api/posts');

// Alternative with useFetch
const { data: posts, pending, error } = await useFetch('/api/posts');

// With reactive parameters
const page = ref(1);
const { data: posts } = await useFetch('/api/posts', {
  query: { page }
});
</script>
```_

### Clientseitige Daten Fetching
```vue
<template>
  <div>
    <button @click="loadPosts">Load Posts</button>
    <div v-if="pending">Loading...</div>
    <div v-else-if="error">Error: {{ error }}</div>
    <div v-else>
      <div v-for="post in posts" :key="post.id">
        <h2>{{ post.title }}</h2>
      </div>
    </div>
  </div>
</template>

<script setup>
const posts = ref([]);
const pending = ref(false);
const error = ref(null);

const loadPosts = async () => {
  pending.value = true;
  error.value = null;

  try {
    posts.value = await $fetch('/api/posts');
  } catch (err) {
    error.value = err.message;
  } finally {
    pending.value = false;
  }
};
</script>
```_

### Advanced Data Fetching
```vue
<script setup>
// Lazy loading
const { data: posts, pending } = await useLazyFetch('/api/posts');

// With caching
const { data: user } = await useFetch(`/api/users/${userId}`, {
  key: `user-${userId}`,
  server: true
});

// With transformation
const { data: posts } = await useFetch('/api/posts', {
  transform: (data: any[]) => data.map(post => ({
    ...post,
    formattedDate: new Date(post.createdAt).toLocaleDateString()
  }))
});

// With error handling
const { data: posts, error } = await useFetch('/api/posts', {
  onResponseError({ request, response, options }) {
    console.error('Response error:', response.status);
  },
  onRequestError({ request, options, error }) {
    console.error('Request error:', error);
  }
});

// Refresh data
const { data: posts, refresh } = await useFetch('/api/posts');

// Refresh manually
await refresh();
</script>
```_

### Daten Fetching mit Pinia
```typescript
// stores/posts.ts
export const usePostsStore = defineStore('posts', () => {
  const posts = ref([]);
  const loading = ref(false);
  const error = ref(null);

  const fetchPosts = async () => {
    loading.value = true;
    error.value = null;

    try {
      const data = await $fetch('/api/posts');
      posts.value = data;
    } catch (err) {
      error.value = err.message;
    } finally {
      loading.value = false;
    }
  };

  const addPost = async (post: CreatePostData) => {
    const newPost = await $fetch('/api/posts', {
      method: 'POST',
      body: post
    });
    posts.value.unshift(newPost);
  };

  return {
    posts: readonly(posts),
    loading: readonly(loading),
    error: readonly(error),
    fetchPosts,
    addPost
  };
});
```_

## Staatliche Verwaltung

### Pinia Setup
```bash
# Install Pinia
npm install pinia @pinia/nuxt
```_

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@pinia/nuxt']
});
```_

### Pinia Store
```typescript
// stores/auth.ts
export const useAuthStore = defineStore('auth', () => {
  // State
  const user = ref<User | null>(null);
  const token = ref<string | null>(null);

  // Getters
  const isAuthenticated = computed(() => !!user.value);
  const isAdmin = computed(() => user.value?.role === 'admin');

  // Actions
  const login = async (credentials: LoginCredentials) => {
    try {
      const response = await $fetch('/api/auth/login', {
        method: 'POST',
        body: credentials
      });

      user.value = response.user;
      token.value = response.token;

      // Store in cookie
      const tokenCookie = useCookie('auth-token');
      tokenCookie.value = response.token;

      return response;
    } catch (error) {
      throw error;
    }
  };

  const logout = async () => {
    try {
      await $fetch('/api/auth/logout', { method: 'POST' });
    } finally {
      user.value = null;
      token.value = null;

      const tokenCookie = useCookie('auth-token');
      tokenCookie.value = null;
    }
  };

  const fetchUser = async () => {
    try {
      const userData = await $fetch('/api/auth/me');
      user.value = userData;
    } catch (error) {
      // Token might be invalid
      logout();
    }
  };

  return {
    user: readonly(user),
    token: readonly(token),
    isAuthenticated,
    isAdmin,
    login,
    logout,
    fetchUser
  };
});
```_

### Speicher in Komponenten verwenden
```vue
<template>
  <div>
    <div v-if="isAuthenticated">
      <p>Welcome, {{ user.name }}!</p>
      <button @click="logout">Logout</button>
    </div>
    <div v-else>
      <form @submit.prevent="handleLogin">
        <input v-model="email" type="email" placeholder="Email" required />
        <input v-model="password" type="password" placeholder="Password" required />
        <button type="submit" :disabled="loading">Login</button>
      </form>
    </div>
  </div>
</template>

<script setup>
const authStore = useAuthStore();
const { user, isAuthenticated } = storeToRefs(authStore);

const email = ref('');
const password = ref('');
const loading = ref(false);

const handleLogin = async () => {
  loading.value = true;

  try {
    await authStore.login({
      email: email.value,
      password: password.value
    });

    await navigateTo('/dashboard');
  } catch (error) {
    console.error('Login failed:', error);
  } finally {
    loading.value = false;
  }
};

const logout = async () => {
  await authStore.logout();
  await navigateTo('/');
};
</script>
```_

### Staat
```typescript
// stores/cart.ts
export const useCartStore = defineStore('cart', () => {
  const items = ref([]);

  // Persist to localStorage
  const persistedItems = useCookie('cart-items', {
    default: () => [],
    serializer: {
      read: (value: string) => {
        try {
          return JSON.parse(value);
        } catch {
          return [];
        }
      },
      write: (value: any[]) => JSON.stringify(value)
    }
  });

  // Initialize from persisted data
  onMounted(() => {
    items.value = persistedItems.value;
  });

  // Watch for changes and persist
  watch(items, (newItems) => {
    persistedItems.value = newItems;
  }, { deep: true });

  const addItem = (product: Product) => {
    const existingItem = items.value.find(item => item.id === product.id);

    if (existingItem) {
      existingItem.quantity++;
    } else {
      items.value.push({ ...product, quantity: 1 });
    }
  };

  const removeItem = (productId: string) => {
    const index = items.value.findIndex(item => item.id === productId);
    if (index > -1) {
      items.value.splice(index, 1);
    }
  };

  const total = computed(() => {
    return items.value.reduce((sum, item) => sum + (item.price * item.quantity), 0);
  });

  return {
    items: readonly(items),
    total,
    addItem,
    removeItem
  };
});
```_

## Styling

### CSS und SCSS
```vue
<template>
  <div class="component">
    <h1 class="title">Hello World</h1>
    <p class="description">This is a Nuxt component</p>
  </div>
</template>

<style scoped>
.component {
  padding: 2rem;
  background: #f8f9fa;
}

.title {
  color: #2c3e50;
  font-size: 2rem;
  margin-bottom: 1rem;
}

.description {
  color: #7f8c8d;
  line-height: 1.6;
}
</style>

<!-- SCSS support -->
<style lang="scss" scoped>
$primary-color: #3498db;
$secondary-color: #2c3e50;

.component {
  padding: 2rem;

  .title {
    color: $primary-color;
    font-size: 2rem;

    &:hover {
      color: darken($primary-color, 10%);
    }
  }

  .description {
    color: $secondary-color;
  }
}
</style>
```_

### Tailwind CSS
```bash
# Install Tailwind CSS
npm install --save-dev @nuxtjs/tailwindcss
```_

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/tailwindcss']
});
```_

```vue
<template>
  <div class="min-h-screen bg-gray-100">
    <header class="bg-white shadow">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex justify-between h-16">
          <div class="flex items-center">
            <h1 class="text-xl font-semibold text-gray-900">My App</h1>
          </div>
          <nav class="flex space-x-8">
            <NuxtLink 
              to="/" 
              class="text-gray-500 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium"
            >
              Home
            </NuxtLink>
            <NuxtLink 
              to="/about" 
              class="text-gray-500 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium"
            >
              About
            </NuxtLink>
          </nav>
        </div>
      </div>
    </header>

    <main class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
      <slot />
    </main>
  </div>
</template>
```_

### CSS Module
```vue
<template>
  <div :class="$style.container">
    <h1 :class="$style.title">CSS Modules</h1>
    <p :class="$style.description">Scoped and modular CSS</p>
  </div>
</template>

<style module>
.container {
  padding: 2rem;
  background: #f8f9fa;
}

.title {
  color: #2c3e50;
  font-size: 2rem;
}

.description {
  color: #7f8c8d;
}
</style>
```_

### Global Styles
```css
/* assets/css/main.css */
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

/* Custom global styles */
body {
  font-family: 'Inter', sans-serif;
}

.btn {
  @apply px-4 py-2 rounded font-medium transition-colors;
}

.btn-primary {
  @apply bg-blue-600 text-white hover:bg-blue-700;
}

.btn-secondary {
  @apply bg-gray-600 text-white hover:bg-gray-700;
}
```_

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css']
});
```_

## Plugins

### Clientseitige Plugins
```typescript
// plugins/vue-toastification.client.ts
import Toast, { POSITION } from 'vue-toastification';
import 'vue-toastification/dist/index.css';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(Toast, {
    position: POSITION.TOP_RIGHT,
    timeout: 3000,
    closeOnClick: true,
    pauseOnFocusLoss: true,
    pauseOnHover: true,
    draggable: true,
    draggablePercent: 0.6,
    showCloseButtonOnHover: false,
    hideProgressBar: false,
    closeButton: 'button',
    icon: true,
    rtl: false
  });
});
```_

### Serverseitige Plugins
```typescript
// plugins/api.server.ts
export default defineNuxtPlugin(async (nuxtApp) => {
  // Server-side initialization
  const config = useRuntimeConfig();

  // Setup API client
  const api = $fetch.create({
    baseURL: config.public.apiBase,
    headers: {
      'Authorization': `Bearer ${config.apiSecret}`
    }
  });

  // Provide to app
  return {
    provide: {
      api
    }
  };
});
```_

### Universal Plugins
```typescript
// plugins/pinia-persistence.ts
export default defineNuxtPlugin(() => {
  // This runs on both client and server
  const nuxtApp = useNuxtApp();

  // Setup Pinia persistence
  if (process.client) {
    nuxtApp.$pinia.use(({ store }) => {
      // Persist store state
      const stored = localStorage.getItem(`pinia-${store.$id}`);
      if (stored) {
        store.$patch(JSON.parse(stored));
      }

      store.$subscribe((mutation, state) => {
        localStorage.setItem(`pinia-${store.$id}`, JSON.stringify(state));
      });
    });
  }
});
```_

### Plugin mit Composables
```typescript
// plugins/auth.ts
export default defineNuxtPlugin(async () => {
  const { $fetch } = useNuxtApp();
  const user = useState('auth.user', () => null);

  // Check for existing session
  if (process.client) {
    const token = useCookie('auth-token');

    if (token.value) {
      try {
        const userData = await $fetch('/api/auth/me', {
          headers: {
            Authorization: `Bearer ${token.value}`
          }
        });
        user.value = userData;
      } catch (error) {
        // Invalid token, clear it
        token.value = null;
      }
    }
  }

  return {
    provide: {
      auth: {
        user,
        login: async (credentials: any) => {
          const response = await $fetch('/api/auth/login', {
            method: 'POST',
            body: credentials
          });

          user.value = response.user;
          const token = useCookie('auth-token');
          token.value = response.token;

          return response;
        },
        logout: () => {
          user.value = null;
          const token = useCookie('auth-token');
          token.value = null;
        }
      }
    }
  };
});
```_

## Module

### Installation von Modulen
```bash
# Popular Nuxt modules
npm install @nuxtjs/tailwindcss
npm install @nuxt/content
npm install @pinia/nuxt
npm install @nuxtjs/google-fonts
npm install @nuxt/image
npm install @vueuse/nuxt
```_

### Modulkonfiguration
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxtjs/tailwindcss',
    '@nuxt/content',
    '@pinia/nuxt',
    '@nuxtjs/google-fonts',
    '@nuxt/image',
    '@vueuse/nuxt'
  ],

  // Module-specific configuration
  googleFonts: {
    families: {
      Inter: [400, 500, 600, 700],
      'Fira Code': [400, 500]
    }
  },

  content: {
    highlight: {
      theme: 'github-dark'
    }
  },

  image: {
    cloudinary: {
      baseURL: 'https://res.cloudinary.com/demo/image/upload/'
    }
  }
});
```_

### Inhaltsmodul
```vue
<!-- pages/blog/[...slug].vue -->
<template>
  <div>
    <ContentDoc />
  </div>
</template>

<!-- Alternative with custom rendering -->
<template>
  <article>
    <header>
      <h1>{{ data.title }}</h1>
      <p>{{ data.description }}</p>
      <time>{{ formatDate(data.date) }}</time>
    </header>

    <ContentRenderer :value="data" />
  </article>
</template>

<script setup>
const { data } = await useAsyncData('blog-post', () => 
  queryContent('/blog').where({ _path: useRoute().path }).findOne()
);

if (!data.value) {
  throw createError({
    statusCode: 404,
    statusMessage: 'Post not found'
  });
}

const formatDate = (date: string) => {
  return new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
};
</script>
```_

### Bildmodul
```vue
<template>
  <div>
    <!-- Optimized images -->
    <NuxtImg
      src="/hero.jpg"
      alt="Hero image"
      width="800"
      height="600"
      loading="lazy"
    />

    <!-- Responsive images -->
    <NuxtPicture
      src="/responsive.jpg"
      alt="Responsive image"
      :img-attrs="{
        class: 'responsive-image',
        style: 'display: block; margin: auto;'
      }"
    />

    <!-- Cloudinary integration -->
    <NuxtImg
      provider="cloudinary"
      src="/sample.jpg"
      width="400"
      height="300"
      :modifiers="{ quality: 'auto', format: 'auto' }"
    />
  </div>
</template>
```_

## Server-Side Rendering

### SSR Konfiguration
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true, // Enable SSR (default)

  // Nitro configuration
  nitro: {
    prerender: {
      routes: ['/sitemap.xml', '/robots.txt']
    }
  },

  // Route rules
  routeRules: {
    // Homepage pre-rendered at build time
    '/': { prerender: true },

    // Product page generated on-demand, revalidates in background
    '/products/**': { isr: true },

    // Blog post cached for 1 hour
    '/blog/**': { isr: 3600 },

    // Admin dashboard renders only on client-side
    '/admin/**': { ssr: false },

    // API routes
    '/api/**': { cors: true }
  }
});
```_

### Hybrid Rendering
```vue
<!-- pages/products/[id].vue -->
<template>
  <div>
    <h1>{{ product.name }}</h1>
    <p>{{ product.description }}</p>
    <p>Price: ${{ product.price }}</p>

    <!-- Client-side only component -->
    <ClientOnly>
      <ProductReviews :product-id="product.id" />
      <template #fallback>
        <div>Loading reviews...</div>
      </template>
    </ClientOnly>
  </div>
</template>

<script setup>
// This runs on server for SSR
const route = useRoute();
const { data: product } = await $fetch(`/api/products/${route.params.id}`);

// Define route rules
defineRouteRules({
  isr: 3600 // Regenerate every hour
});
</script>
```_

### Strategische Site Generation
```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: [
        '/',
        '/about',
        '/contact'
      ]
    }
  }
});
```_

```bash
# Generate static site
npm run generate

# Preview generated site
npm run preview
```_

### ISR (Incremental Static Regeneration)
```vue
<script setup>
// Enable ISR with 1 hour revalidation
defineRouteRules({
  isr: 3600
});

// Fetch data that will be cached
const { data: posts } = await $fetch('/api/posts');
</script>
```_

## API Routen

### Grundlegende API Routen
```typescript
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
  // Get query parameters
  const query = getQuery(event);
| const page = parseInt(query.page as string) |  | 1; |
| const limit = parseInt(query.limit as string) |  | 10; |

  // Fetch users from database
  const users = await getUsersFromDB({ page, limit });

  return {
    users,
    pagination: {
      page,
      limit,
      total: users.length
    }
  };
});

// server/api/users.post.ts
export default defineEventHandler(async (event) => {
  // Get request body
  const body = await readBody(event);

  // Validate input
| if (!body.email |  | !body.name) { |
    throw createError({
      statusCode: 400,
      statusMessage: 'Email and name are required'
    });
  }

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

  // Set response status
  setResponseStatus(event, 201);

  return user;
});
```_

### Dynamische API Routen
```typescript
// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id');

  if (!id) {
    throw createError({
      statusCode: 400,
      statusMessage: 'User ID is required'
    });
  }

  const user = await getUserById(id);

  if (!user) {
    throw createError({
      statusCode: 404,
      statusMessage: 'User not found'
    });
  }

  return user;
});

// server/api/users/[id].put.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id');
  const body = await readBody(event);

  const updatedUser = await updateUser(id, body);

  return updatedUser;
});

// server/api/users/[id].delete.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id');

  await deleteUser(id);

  setResponseStatus(event, 204);
  return null;
});
```_

### Middleware
```typescript
// server/middleware/auth.ts
export default defineEventHandler(async (event) => {
  // Only apply to API routes
  if (!event.node.req.url?.startsWith('/api/')) {
    return;
  }

  // Skip auth for public routes
  const publicRoutes = ['/api/auth/login', '/api/auth/register'];
  if (publicRoutes.includes(event.node.req.url)) {
    return;
  }

  // Check authorization header
  const authorization = getHeader(event, 'authorization');

  if (!authorization) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Authorization header required'
    });
  }

  const token = authorization.replace('Bearer ', '');

  try {
    const user = await verifyToken(token);
    event.context.user = user;
  } catch (error) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Invalid token'
    });
  }
});
```_

### Datei hochladen
```typescript
// server/api/upload.post.ts
import { writeFile } from 'fs/promises';
import { join } from 'path';

export default defineEventHandler(async (event) => {
  const form = await readMultipartFormData(event);

  if (!form) {
    throw createError({
      statusCode: 400,
      statusMessage: 'No file uploaded'
    });
  }

  const file = form.find(item => item.name === 'file');

  if (!file) {
    throw createError({
      statusCode: 400,
      statusMessage: 'File field is required'
    });
  }

  // Generate unique filename
  const filename = `${Date.now()}-${file.filename}`;
  const filepath = join(process.cwd(), 'public/uploads', filename);

  // Save file
  await writeFile(filepath, file.data);

  return {
    filename,
    url: `/uploads/${filename}`,
    size: file.data.length
  };
});
```_

## Bereitstellung

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

# Deploy to Vercel
vercel

# Deploy to production
vercel --prod
```_

```json
// vercel.json
{
  "framework": "nuxtjs",
  "buildCommand": "npm run build",
  "devCommand": "npm run dev",
  "installCommand": "npm install"
}
```_

### Netlify Deployment
```toml
# netlify.toml
[build]
  command = "npm run build"
  publish = ".output/public"

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

[build.environment]
  NODE_VERSION = "18"
```_

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

WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production && npm cache clean --force

# Copy source code
COPY . .

# Build application
RUN npm run build

# Expose port
EXPOSE 3000

# Start application
CMD ["node", ".output/server/index.mjs"]

Static Hosting

```typescript // nuxt.config.ts export default defineNuxtConfig({ nitro: { prerender: { routes: ['/sitemap.xml'] } },

// For static hosting ssr: false, // Disable SSR for SPA mode

// Or use static generation nitro: { prerender: { crawlLinks: true } } }); ```_

Umweltvariablen

```bash

.env

NUXT_SECRET_KEY=your-secret-key NUXT_PUBLIC_API_URL=https://api.example.com

.env.production

NUXT_SECRET_KEY=production-secret-key NUXT_PUBLIC_API_URL=https://api.production.com ```_

```typescript // nuxt.config.ts export default defineNuxtConfig({ runtimeConfig: { // Private keys (only available on server-side) secretKey: process.env.NUXT_SECRET_KEY,

// Public keys (exposed to client-side)
public: {
  apiUrl: process.env.NUXT_PUBLIC_API_URL
}

} }); ```_

Prüfung

Vitest Setup

```bash

Install testing dependencies

npm install --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ```_

```typescript // vitest.config.ts import { defineConfig } from 'vitest/config'; import vue from '@vitejs/plugin-vue';

export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom' } }); ```_

Komponentenprüfung

```typescript // tests/components/Button.test.ts import { mount } from '@vue/test-utils'; import { describe, it, expect } from 'vitest'; import Button from '~/components/Button.vue';

describe('Button', () => { it('renders properly', () => { const wrapper = mount(Button, { props: { text: 'Hello world' } });

expect(wrapper.text()).toContain('Hello world');

});

it('emits click event', async () => { const wrapper = mount(Button);

await wrapper.trigger('click');

expect(wrapper.emitted()).toHaveProperty('click');

}); }); ```_

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', async ({ page }) => { await page.goto('/');

await expect(page).toHaveTitle(/Nuxt/); await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible(); }); ```_

Leistungsoptimierung

Bundanalyse

```bash

Analyze bundle

npm run build -- --analyze

Or use webpack-bundle-analyzer

npm install --save-dev webpack-bundle-analyzer ```_

Code Splitting

```vue

```_

Bildoptimierung

```vue ```_

Caching-Strategien

```typescript // nuxt.config.ts export default defineNuxtConfig({ routeRules: { // Cache homepage for 1 hour '/': { isr: 3600 },

// Cache blog posts for 1 day
'/blog/**': { isr: 86400 },

// Prerender at build time
'/about': { prerender: true }

} }); ```_

Fehlerbehebung

Gemeinsame Themen

Hydratation Mismatch

```vue ```_

Speicherleaks

```vue

```_

Fehler erstellen

```bash

Clear Nuxt cache

rm -rf .nuxt .output

Clear node_modules

rm -rf node_modules package-lock.json npm install

Check for TypeScript errors

npx nuxi typecheck ```_

Best Practices

Projektstruktur

```bash

Recommended structure

components/ ├── ui/ # Basic UI components ├── forms/ # Form components └── layout/ # Layout components

composables/ ├── useAuth.ts # Authentication ├── useApi.ts # API calls └── useState.ts # State management

utils/ ├── validation.ts # Validation helpers ├── formatting.ts # Formatting utilities └── constants.ts # App constants ```_

Leistung

```vue

```_

SEO

```vue

```_

--

Zusammenfassung

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

  • Dateibasiertes Routing: Automatisches Routing basierend auf Dateistruktur
  • *Server-Side Rendering: Eingebaute SSR mit hybriden Rendering Optionen
  • ** Auto-Importe*: Automatische Komponente und komponierbare Importe
  • Datenerhebung: Leistungsstarke Daten mit Cache und Reaktivität
  • Module: Reiches Ökosystem von Modulen für erweiterte Funktionalität
  • Leistung: Eingebaute Optimierungen und Codeteilung

Für optimale Ergebnisse nutzen Sie serverseitige Rendering für bessere SEO, verwenden Sie Composables für wiederverwendbare Logik, implementieren Sie richtige Cache-Strategien und folgen Sie Nuxt.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(); }