Skip to content

Integration: Nuxt 3

Status: Produktiv seit 2026-05-20. Funktioniert mit Nuxt 3.x und der Nuxt-Bridge.

60-Sekunden-Setup

bash
# In deinem Nuxt-Projekt:
npx @peacock/cli init nuxt

Was passiert:

  1. Erkennung: nuxt.config.{js,mjs,ts} oder nuxt in package.json.
  2. .env: Fügt NUXT_PUBLIC_PEACOCK_API_BASE_URL, NUXT_PUBLIC_PEACOCK_SPACE, NUXT_PEACOCK_TOKEN idempotent hinzu.
  3. pages/[...slug].vue wird scaffold-iert mit useAsyncData + serverseitigem Fetch.
  4. Druckt den Install-Befehl für dein erkanntes Package-Manager.

Manuell danach:

bash
pnpm add @peacock/sdk-js
# .env mit echten Werten füllen
pnpm dev

nuxt.config.ts

Füge die runtimeConfig-Sektion hinzu — Nuxt liest dann NUXT_*-Env-Vars automatisch:

ts
export default defineNuxtConfig({
  runtimeConfig: {
    peacockToken: '',         // gefüllt von NUXT_PEACOCK_TOKEN (server-only)
    public: {
      peacockApiBaseUrl: '',  // gefüllt von NUXT_PUBLIC_PEACOCK_API_BASE_URL
      peacockSpace: '',       // gefüllt von NUXT_PUBLIC_PEACOCK_SPACE
    },
  },
});

Schlüssel ohne public:-Wrapping sind server-only und nie im Client-Bundle.

Generierte Sample-Page

pages/[...slug].vue:

vue
<script setup lang="ts">
import { makeApi } from '@peacock/sdk-js';

const route = useRoute();
const config = useRuntimeConfig();

const slugSegments = (route.params['slug'] ?? []) as string[];
const path = '/' + slugSegments.join('/');

const { data: story, error } = await useAsyncData(
  `story-${path}`,
  async () => {
    const api = makeApi(config.peacockToken as string, {
      baseUrl: config.public.peacockApiBaseUrl as string,
    });
    const result = await api.cdnStory(config.public.peacockSpace as string, path);
    if (result.status !== 'ok') {
      throw createError({ statusCode: 404, statusMessage: 'Story not found' });
    }
    return result.data.data;
  },
);

if (error.value) throw error.value;
</script>

<template>
  <main>
    <pre>{{ story?.content }}</pre>
  </main>
</template>

Der Fetch passiert serverseitig beim ersten Request (useAsyncData), Nuxt hydratet den Client mit dem Ergebnis — kein zusätzlicher API-Roundtrip im Browser.

Eigene Block-Renderer

Map jeden _component auf eine Vue-Komponente:

vue
<script setup lang="ts">
import Hero from '~/components/peacock/Hero.vue';
import FAQ from '~/components/peacock/FAQ.vue';
import TextImage from '~/components/peacock/TextImage.vue';

const blockMap: Record<string, Component> = {
  hero: Hero,
  faq: FAQ,
  text_image: TextImage,
};
</script>

<template>
  <component
    v-for="(block, i) in (story?.content.body as any[])"
    :key="i"
    :is="blockMap[block._component] ?? 'div'"
    v-bind="block"
  />
</template>

Caching & Performance

useAsyncData cached den ersten Server-Fetch in den payload.json der Page — Folge-Navigationen via Nuxt-Router lösen keinen erneuten Peacock-Call aus. Bei force: true (z.B. nach Webhook) wird neu geholt.

Für Edge-Deploys (Cloudflare Pages mit Nitro-Preset cloudflare): der cdnStory()-Endpoint setzt ETag + Cache-Control: max-age=60, stale-while-revalidate=300, also bekommst du SWR-Caching gratis.

Was noch fehlt

  • Dedicated @peacock/nuxt-Modul: Phase-9-Polish (auto-imports, devtools-tab). Heute ist das SDK-Pattern oben vollständig funktional.