Migratie naar v4

Een uitgebreide handleiding voor het migreren van uw applicatie van Nuxt UI v3 naar Nuxt UI v4.

Nuxt UI v4 markeert een belangrijke mijlpaal: Nuxt UI en Nuxt UI Pro zijn nu verenigd in een enkele, volledig open-source en gratis library. U heeft nu toegang tot meer dan 125 productieklare componenten, allemaal beschikbaar in het @nuxt/ui-pakket.

Nuxt UI v4 vereist Nuxt 4.1 of later vanwege enkele afhankelijkheden. Zorg ervoor dat u een upgrade uitvoert voordat u naar Nuxt UI v4 migreert.

Deze gids biedt stapsgewijze instructies om uw applicatie van v3 naar v4 te migreren.

Migreer uw project

Van Nuxt UI Pro

  1. Vervang @nuxt/ui-pro door @nuxt/ui in je package.json:
pnpm remove @nuxt/ui-pro
pnpm add @nuxt/ui tailwindcss
  1. Vervang @nuxt/ui-pro door @nuxt/ui in je nuxt.config.ts:
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
-   '@nuxt/ui-pro',
+   '@nuxt/ui'
  ]
})
  1. Vervang @nuxt/ui-pro door @nuxt/ui in je vite.config.ts:
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
- import uiPro from '@nuxt/ui-pro/vite'
+ import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
-   uiPro({
+   ui({
      ui: {
        colors: {
          primary: 'green',
          neutral: 'slate'
        }
      }
    })
  ]
})
  1. Gebruik de ui-toets in plaats van uiPro in uw app.config.ts:
app/app.config.ts
export default defineAppConfig({
  ui: {
    colors: {
      primary: 'green',
      neutral: 'slate'
    },
+   pageCard: {
+     slots: {
+       root: 'rounded-xl',
+     }
+   }
  },
- uiPro: {
-   pageCard: {
-     slots: {
-       root: 'rounded-xl',
-     }
-   }
- }
})
  1. Gebruik de ui toets in plaats van uiPro in je vite.config.ts:
vite.config.ts
export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        colors: {
          primary: 'green',
          neutral: 'slate'
        },
+       pageCard: {
+         slots: {
+           root: 'rounded-xl',
+         }
+       }
      },
-     uiPro: {
-       pageCard: {
-         slots: {
-           root: 'rounded-xl',
-         }
-       }
-     }
    })
  ]
})
  1. Vervang @nuxt/ui-pro door @nuxt/ui in je CSS:
app/assets/css/main.css
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
Als u tegelijkertijd met Nuxt UI v4 een upgrade uitvoert naar Nuxt 4, zorg er dan voor dat u de @source-richtlijn bijwerkt zodat deze overeenkomt met de nieuwe directorystructuur.
app/assets/css/main.css
@import "tailwindcss";
@import "@nuxt/ui";

- @source "../../content/**/*";
+ @source "../../../content/**/*";
src/assets/css/main.css
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
  1. Vervang @nuxt/ui-pro door @nuxt/ui in uw import:
- import type { BannerProps } from '@nuxt/ui-pro'
+ import type { BannerProps } from '@nuxt/ui'

Van Nuxt UI

  1. Bij het upgraden van Nuxt UI v3 hoeft u alleen maar te updaten naar v4:
pnpm add @nuxt/ui tailwindcss

Wijzigingen van v3

Let na het upgraden naar Nuxt UI v4 op de volgende belangrijke wijzigingen:

Hernoemde knop Groep

De ButtonGroup component is hernoemd naar FieldGroup:

<template>
- <UButtonGroup>
+ <UFieldGroup>
    <UButton label="Button" />
    <UButton icon="i-lucide-chevron-down" />
+ </UFieldGroup>
- </UButtonGroup>
</template>

Hernoemde paginaMarquee

De PageMarquee component is hernoemd naar Marquee:

<template>
- <UPageMarquee :items="items" />
+ <UMarquee :items="items" />
</template>

Verwijderde paginaAccordeon

De PageAccordion component is verwijderd ten gunste van Accordion:

<template>
- <UPageAccordion
+ <UAccordion
    :items="items"
+   :unmount-on-hide="false"
+   :ui="{ trigger: 'text-base', body: 'text-base text-muted' }"
  />
</template>
De PageAccordion-component was een wikkel die unmount-on-hide op false instelde en de ui-prop aanpaste.

Hernoemd model modifiers

De modelModifiers vorm gebruikt door Input, InputNumber en Textarea is veranderd in v4:

  1. De nullify modifier werd hernoemd naar nullable (het converteert lege / lege waarden naar null).
  2. Er is een nieuwe optional modifier toegevoegd (deze converteert lege / lege waarden naar undefined).
- <UInput v-model.nullify="value" />
+ <UInput v-model.nullable="value" />
- <UTextarea v-model="value" :model-modifiers="{ nullify: true }" />
+ <UTextarea v-model="value" :model-modifiers="{ nullable: true }" />

Gebruik nullable wanneer u lege waarden wilt als null, en optional wanneer u undefined verkiest voor afwezige waarden.

Wijzigingen aan Form component

De Form-component is verbeterd in v4 met beter statusbeheer en geneste formulierafhandeling. Dit zijn de belangrijkste wijzigingen waarvan u op de hoogte moet zijn:

  1. Schema **transformations wordt alleen ** toegepast op de @submit data en muteert niet langer de status van het formulier. Dit zorgt voor een betere voorspelbaarheid en voorkomt onverwachte toestandsmutaties.
  2. Nested formulieren moeten explicitly worden ingeschakeld met de nested prop. Dit maakt het gedrag van de componenten explicieter en voorkomt het per ongeluk maken van geneste formulieren.
  3. Nested formulieren zouden nu een name prop moeten bieden (vergelijkbaar met UFormField) en zullen automatisch hun status overnemen van hun bovenliggende vorm.
<template>
  <UForm :state="state" :schema="schema" @submit="onSubmit">
    <UFormField label="Customer" name="customer">
      <UInput v-model="state.customer" placeholder="Wonka Industries" />
    </UFormField>

    <div v-for="(item, index) in state.items" :key="index">
      <UForm
-       :state="item"
+       :name="`items.${index}`"
        :schema="itemSchema"
+       nested
      >
        <UFormField :label="!index ? 'Description' : undefined" name="description">
          <UInput v-model="item.description" />
        </UFormField>
        <UFormField :label="!index ? 'Price' : undefined" name="price">
          <UInput v-model="item.price" type="number" />
        </UFormField>
      </UForm>
    </div>
  </UForm>
</template>

Verwijderde verouderde hulpprogramma 's

Sommige Nuxt Content-hulpprogramma 's die eerder beschikbaar waren in Nuxt UI Pro zijn removed in v4:

  • findPageBreadcrumb
  • findPageHeadline

Deze worden nu volledig geleverd door Nuxt Content. Zorg ervoor dat u uw import en gebruik dienovereenkomstig bijwerkt.

- import { findPageHeadline } from '@nuxt/ui-pro/utils/content'
+ import { findPageHeadline } from '@nuxt/content/utils'

- import { findPageBreadcrumb } from '@nuxt/ui-pro/utils/content'
+ import { findPageBreadcrumb } from '@nuxt/content/utils'

AI SDK migratie (optioneel)

Deze sectie is alleen van toepassing als u de AI SDK- en chatcomponenten gebruikt (ChatMessage, ChatMessages, ChatPrompt, ChatPromptSubmit, ChatPalette). Als u geen AI-functies gebruikt, kunt u deze sectie overslaan.

  1. Update @ai-sdk/vue- en ai-afhankelijkheden in uw package.json en voeg Comark toe (vervangt @nuxtjs/mdc voor het weergeven van AI-reacties als streaming Markdown):
{
  "dependencies": {
-   "@ai-sdk/vue": "^1.2.x",
+   "@ai-sdk/vue": "^4.0.x",
-   "ai": "^4.3.x",
+   "ai": "^7.0.x",
+   "@comark/nuxt": "latest"
  }
}

Voeg @comark/nuxt toe aan uw modules:

nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxt/ui',
+   '@comark/nuxt'
  ]
})
{
  "dependencies": {
-   "@ai-sdk/vue": "^1.2.x",
+   "@ai-sdk/vue": "^4.0.x",
-   "ai": "^4.3.x",
+   "ai": "^7.0.x",
+   "@comark/vue": "latest"
  }
}
  1. De useChat composable API is gewijzigd: input en handleSubmit zijn verwijderd ten gunste van sendMessage, en messages is nu een ref die je direct instelt:
<script setup lang="ts">
  import { useChat } from '@ai-sdk/vue'

- const { messages, input, handleSubmit, status, error, reload, setMessages } = useChat()
+ const { messages, status, error, sendMessage, regenerate, stop } = useChat()
+ const input = ref('')
+
+ function handleSubmit() {
+   sendMessage({ text: input.value })
+   input.value = ''
+ }
</script>
  1. Berichten gebruiken nu parts in plaats van content:
// When manually creating messages
- setMessages([{
+ messages.value = [{
  id: '1',
  role: 'user',
- content: 'Hello world'
+ parts: [{ type: 'text', text: 'Hello world' }]
- }])
+ }]

// In templates
<template>
- <UChatMessage :content="message.content" />
+ <UChatMessage :parts="message.parts" />
</template>
  1. Sommige methoden zijn hernoemd:
// Regenerate the last message
- reload()
+ regenerate()
  1. Vervang <MDC> door <Markdown> voor op onderdelen gebaseerde weergave. De Markdown-component is speciaal gebouwd voor het streamen van Markdown, het geeft stapsgewijs tokens weer wanneer ze van de AI komen. Gebruik AI SDK-helpers en het isPartStreaming-hulpprogramma van @nuxt/ui/utils/ai.
Wanneer u de shiki-plug-in gebruikt, voegt u de volgende CSS toe aan uw stylesheet voor ondersteuning in de donkere modus:
main.css
html.dark .shiki span {
  color: var(--shiki-dark) !important;
  background-color: var(--shiki-dark-bg) !important;
  font-style: var(--shiki-dark-font-style) !important;
  font-weight: var(--shiki-dark-font-weight) !important;
  text-decoration: var(--shiki-dark-text-decoration) !important;
}
<script setup lang="ts">
import { isReasoningUIPart, isTextUIPart } from 'ai'
import { isPartStreaming } from '@nuxt/ui/utils/ai'
import shiki from '@comark/nuxt/plugins/shiki'

const plugins = [shiki()]
</script>

<template>
  <UChatMessages :messages="messages" :status="status">
    <template #content="{ message }">
      <template v-for="(part, index) in message.parts" :key="`${message.id}-${part.type}-${index}`">
        <UChatReasoning
          v-if="isReasoningUIPart(part)"
          :text="part.text"
          :streaming="isPartStreaming(part)"
        >
          <Markdown
            :value="part.text"
            :streaming="isPartStreaming(part)"
            :plugins="plugins"
            class="*:first:mt-0 *:last:mb-0"
          />
        </UChatReasoning>

        <template v-else-if="isTextUIPart(part)">
          <Markdown
            v-if="message.role === 'assistant'"
            :value="part.text"
            :streaming="isPartStreaming(part)"
            :plugins="plugins"
            class="*:first:mt-0 *:last:mb-0"
          />
          <p v-else-if="message.role === 'user'" class="whitespace-pre-wrap">
            {{ part.text }}
          </p>
        </template>
      </template>
    </template>
  </UChatMessages>
</template>
<script setup lang="ts">
import { isReasoningUIPart, isTextUIPart } from 'ai'
import { isPartStreaming } from '@nuxt/ui/utils/ai'
import { Markdown } from '@comark/vue'
import shiki from '@comark/vue/plugins/shiki'

const plugins = [shiki()]
</script>

<template>
  <UChatMessages :messages="messages" :status="status">
    <template #content="{ message }">
      <template v-for="(part, index) in message.parts" :key="`${message.id}-${part.type}-${index}`">
        <UChatReasoning
          v-if="isReasoningUIPart(part)"
          :text="part.text"
          :streaming="isPartStreaming(part)"
        >
          <Markdown
            :value="part.text"
            :streaming="isPartStreaming(part)"
            :plugins="plugins"
            class="*:first:mt-0 *:last:mb-0"
          />
        </UChatReasoning>

        <template v-else-if="isTextUIPart(part)">
          <Markdown
            v-if="message.role === 'assistant'"
            :value="part.text"
            :streaming="isPartStreaming(part)"
            :plugins="plugins"
            class="*:first:mt-0 *:last:mb-0"
          />
          <p v-else-if="message.role === 'user'" class="whitespace-pre-wrap">
            {{ part.text }}
          </p>
        </template>
      </template>
    </template>
  </UChatMessages>
</template>
Raadpleeg de official AI SDK-migratiegidsen voor meer informatie over de AI SDK-wijzigingen.
Bekijk alle wijzigingen in de AI SDK v7 upgrade PR voor een gedetailleerde migratie referentie.