Modul 9: Nuxt Fortgeschritten

Plugins & Module

Erweitere Nuxt mit eigenen Plugins für globale Funktionalität und nutze Community-Module für häufige Anforderungen.

Plugins vs. Module

Nuxt hat zwei Erweiterungsmechanismen, die oft verwechselt werden:

  • Plugins – Laufen beim App-Start, registrieren globale Funktionalität (wie Vue-Plugins, Helper, Interceptors)
  • Module – Erweitern die Nuxt-Build-Konfiguration, können Plugins automatisch registrieren, Routen hinzufügen, etc.
🛤️

Rails-Vergleich

Nuxt Plugins entsprechen Rails Initializers (config/initializers/) – Code, der beim App-Start einmal läuft. Nuxt Module entsprechen Rails Gems + Engines – wiederverwendbare Pakete, die sich in den Build-Prozess einklinken.

Plugins erstellen

Plugins werden im plugins/-Verzeichnis erstellt und automatisch geladen. Ein einfaches Plugin, das einen globalen API-Client bereitstellt:

plugins/api.ts
// plugins/api.ts
export default defineNuxtPlugin(() => {
  const config = useRuntimeConfig()

  const api = $fetch.create({
    baseURL: config.public.apiUrl,
    onRequest({ options }) {
      // Auth-Token automatisch anhängen
      const token = useCookie('auth-token')
      if (token.value) {
        options.headers.set('Authorization', `Bearer ${token.value}`)
      }
    },
    onResponseError({ response }) {
      // Bei 401 zur Login-Seite
      if (response.status === 401) {
        navigateTo('/login')
      }
    }
  })

  return {
    provide: {
      api
    }
  }
})

Den bereitgestellten Wert nutzt du dann überall in deiner App:

pages/produkte.vue
<script setup lang="ts">
// $api ist überall verfügbar dank Plugin
const { $api } = useNuxtApp()

const { data: produkte } = await useAsyncData('produkte', () =>
  $api('/produkte')
)
</script>

<template>
  <div>
    <h1>Produkte</h1>
    <ul>
      <li v-for="p in produkte" :key="p.id">
        {{ p.name }} – {{ p.preis }} €
      </li>
    </ul>
  </div>
</template>
ℹ️

provide/inject

provide im Plugin und useNuxtApp().$api basieren auf Vues Dependency-Injection-System. Der Typ wird automatisch aus dem Plugin abgeleitet – kein manuelles Typing nötig.

Plugin-Reihenfolge & Abhängigkeiten

Plugins werden alphabetisch nach Dateiname geladen. Wenn die Reihenfolge wichtig ist, nutze Zahlen-Präfixe oder die dependsOn-Option:

plugins/01.auth.ts
// plugins/01.auth.ts
export default defineNuxtPlugin({
  name: 'auth',
  async setup() {
    const { fetch: fetchSession } = useUserSession()

    // Session beim App-Start laden
    await fetchSession()

    console.log('Auth-Plugin geladen')
  }
})
plugins/02.api.ts
// plugins/02.api.ts
export default defineNuxtPlugin({
  name: 'api',
  dependsOn: ['auth'], // Wartet bis auth-Plugin fertig ist
  setup() {
    const { user } = useUserSession()

    const api = $fetch.create({
      baseURL: useRuntimeConfig().public.apiUrl,
      onRequest({ options }) {
        if (user.value) {
          options.headers.set('X-User-Id', user.value.id)
        }
      }
    })

    return { provide: { api } }
  }
})
💡

Server/Client-Only Plugins

Benenne Plugins mit .server.ts oder .client.ts, um sie nur auf dem Server oder nur im Browser auszuführen: plugins/analytics.client.ts lädt nur im Browser, plugins/db.server.ts nur auf dem Server.

provide/inject in Plugins

Mit provide stellst du Werte, Funktionen oder ganze Service-Klassen global bereit. Hier ein Beispiel mit einem Toast-Notification-System:

plugins/toast.client.ts
// plugins/toast.client.ts
export default defineNuxtPlugin(() => {
  const toasts = ref<Array<{
    id: number
    message: string
    type: 'success' | 'error' | 'info'
  }>>([])

  let nextId = 0

  const toast = {
    success(message: string) {
      addToast(message, 'success')
    },
    error(message: string) {
      addToast(message, 'error')
    },
    info(message: string) {
      addToast(message, 'info')
    },
    toasts: readonly(toasts)
  }

  function addToast(message: string, type: 'success' | 'error' | 'info') {
    const id = nextId++
    toasts.value.push({ id, message, type })

    // Automatisch nach 3 Sekunden entfernen
    setTimeout(() => {
      toasts.value = toasts.value.filter(t => t.id !== id)
    }, 3000)
  }

  return { provide: { toast } }
})
components/OrderButton.vue
<script setup lang="ts">
const { $toast } = useNuxtApp()

async function bestellen() {
  try {
    await $fetch('/api/bestellungen', {
      method: 'POST',
      body: { produktId: 123 }
    })
    $toast.success('Bestellung erfolgreich aufgegeben!')
  } catch {
    $toast.error('Bestellung fehlgeschlagen.')
  }
}
</script>

<template>
  <button @click="bestellen" class="px-4 py-2 bg-green-500 text-white rounded">
    Jetzt bestellen
  </button>
</template>
ℹ️

Der $-Präfix ($toast) ist eine Nuxt-Konvention für Werte aus Plugins. TypeScript erkennt diese automatisch, wenn du provide im Plugin nutzt.

Nuxt Module

Module sind mächtiger als Plugins – sie können den Build-Prozess modifizieren, automatisch Plugins registrieren, Routen hinzufügen und Konfigurationen erweitern. Die meisten Nuxt-Features (wie useFetch, Auto-Imports) sind selbst als Module implementiert.

Community-Module installieren

Terminal
# Module mit nuxi installieren (empfohlen)
npx nuxi module add @nuxt/image
npx nuxi module add @nuxtjs/i18n
npx nuxi module add @pinia/nuxt

# Oder manuell mit npm
npm install @nuxt/image @nuxtjs/i18n @pinia/nuxt
nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxt/image',
    '@nuxtjs/i18n',
    '@pinia/nuxt',
    '@vueuse/nuxt'
  ],

  // Modul-spezifische Konfiguration
  image: {
    quality: 80,
    formats: ['avif', 'webp']
  },

  i18n: {
    locales: ['de', 'en'],
    defaultLocale: 'de'
  }
})
💡

nuxi module add

npx nuxi module add installiert das Modul und fügt es automatisch zur nuxt.config.ts hinzu. Das spart den manuellen Schritt.

Eigene Module erstellen

Du kannst auch eigene Module erstellen – entweder inline in nuxt.config.ts oder als separate Dateien im modules/-Verzeichnis:

modules/health-check.ts
// modules/health-check.ts
import { defineNuxtModule, addServerHandler } from '@nuxt/kit'

export default defineNuxtModule({
  meta: {
    name: 'health-check',
    configKey: 'healthCheck'
  },

  defaults: {
    path: '/api/health',
    version: '1.0.0'
  },

  setup(options, nuxt) {
    // Server-Route für Health-Check hinzufügen
    addServerHandler({
      route: options.path,
      handler: '~/modules/health-check-handler.ts'
    })

    // Build-Info loggen
    nuxt.hook('build:before', () => {
      console.log(`Health-Check v${options.version} aktiv`)
    })
  }
})

Module im modules/-Verzeichnis werden automatisch geladen. Alternativ kannst du sie explizit in nuxt.config.ts registrieren:

nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    // Community-Module
    '@nuxt/image',

    // Eigenes Modul mit Optionen
    ['~/modules/health-check', {
      path: '/api/health',
      version: '2.0.0'
    }]
  ],

  // Oder via configKey:
  healthCheck: {
    path: '/api/health',
    version: '2.0.0'
  }
})

Die wichtigsten Community-Module

Das Nuxt-Ökosystem bietet Module für fast jeden Anwendungsfall. Hier die nützlichsten für Produktions-Apps:

ModulZweckRails-Äquivalent
@nuxt/imageBild-Optimierung & Lazy Loadingimage_processing Gem
@nuxt/fontsFont-Optimierung (Google Fonts etc.)Asset Pipeline
@nuxtjs/i18nInternationalisierungrails-i18n Gem
nuxt-auth-utilsAuthentifizierung (OAuth, Sessions)devise Gem
@pinia/nuxtState ManagementRails Session / Cache Store
@nuxtjs/sitemapAutomatische Sitemap-Generierungsitemap_generator Gem
@vueuse/nuxt200+ Vue-ComposablesKein direktes Äquivalent
@nuxt/eslintCode-Qualität & Lintingrubocop Gem
💡

Module entdecken

Alle offiziellen und Community-Module findest du auf nuxt.com/modules. Dort kannst du nach Kategorie filtern und siehst die Installations-Statistiken.

Zusammenfassung

ℹ️

Plugin oder Modul?

Plugin = Code, der beim App-Start läuft (z.B. API-Client registrieren, globale Fehlerbehandlung einrichten).
Modul = Code, der den Build-Prozess erweitert (z.B. neue Routen hinzufügen, Webpack/Vite konfigurieren, Plugins automatisch registrieren).

Faustregel: Wenn es nur zur Laufzeit gebraucht wird → Plugin. Wenn es den Build beeinflusst → Modul.