v4로 마이그레이션

응용 프로그램을 Nuxt UI v3에서 Nuxt UI v4로 마이그레이션하는 포괄적인 가이드입니다.A comprehensive guide to migrate your application from Nuxt UI v3 to Nuxt UI v4.

Nuxt UI v4는 중요한 이정표를 표시합니다. **Nuxt UI와 Nuxt UI Pro는 이제 완전히 오픈 소스 및 무료 라이브러리 **로 통합되었습니다. 이제 @nuxt/ui 패키지에서 사용할 수 있는 125+ 프로덕션 준비 구성 요소에 액세스할 수 있습니다.

Nuxt UI v4에는 일부 종속성으로 인해 Nuxt 4.1 또는 laters가 필요합니다. Nuxt UI v4로 마이그레이션하기 전에 업그레이드해야 합니다.

이 가이드에서는 애플리케이션을 v3에서 v4로 마이그레이션하는 단계별 지침을 제공합니다.

프로젝트 마이그레이션

Nuxt UI Pro 에서

  1. xx@nuxt/ui-pro를 package.json에서 @nuxt/ui로 바꿉니다.
pnpm remove @nuxt/ui-pro
pnpm add @nuxt/ui tailwindcss
  1. xx@nuxt/ui-pro를 nuxt.config.ts에서 @nuxt/ui로 대체합니다.
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
-   '@nuxt/ui-pro',
+   '@nuxt/ui'
  ]
})
  1. xxvite.config.ts에서 @nuxt/ui-pro를 @nuxt/ui로 바꿉니다.
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. xapp.config.ts에서 uiPro 대신 ui 키를 사용합니다.
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. xvite.config.ts에서 uiPro 대신 ui 키를 사용하십시오.
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. CSS에서 @nuxt/ui-pro를 @nuxt/ui로 바꿉니다.
app/assets/css/main.css
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
Nuxt UI v4와 동시에 Nuxt 4로 업그레이드하는 경우 @source 지시어를 새 디렉토리 구조에 맞게 업데이트해야 합니다.
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. import에서 @nuxt/ui-pro를 @nuxt/ui로 바꿉니다.
- import type { BannerProps } from '@nuxt/ui-pro'
+ import type { BannerProps } from '@nuxt/ui'

Nuxt UI에서

  1. Nuxt UI v3에서 업그레이드하는 경우 v4로 업데이트하기만 하면 됩니다.
pnpm add @nuxt/ui tailwindcss

v3의 변경 사항

Nuxt UI v4로 업그레이드한 후 다음과 같은 중요한 변경 사항에 유의하십시오.

Renamed ButtonGroup 버튼그룹

ButtonGroup 구성 요소의 이름이 FieldGroup로 변경되었습니다.

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

PageMarquee 이름 바꾸기

PageMarquee 구성 요소의 이름이 Marquee로 변경되었습니다.

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

Removed PageAccordion 페이지아코디언

PageAccordion 구성 요소는 Accordion에 찬성하여 제거되었습니다.

<template>
- <UPageAccordion
+ <UAccordion
    :items="items"
+   :unmount-on-hide="false"
+   :ui="{ trigger: 'text-base', body: 'text-base text-muted' }"
  />
</template>
PageAccordion 구성 요소는 unmount-on-hide를 false로 설정하고 ui prop을 사용자 정의하는 래퍼였습니다.

이름 변경된 모델 수정자

Input, ](/docs/components/input-number) 및 Textarea에 사용되는 modelModifiers 쉐이프가 v4에서 변경되었습니다.

  1. xnullify 수정자의 이름이 nullable로 바뀌었습니다 (비어 있거나 빈 값을 null로 변환).
  2. A 새로운 optional 수정자가 추가되었습니다 (비어 있거나 빈 값을 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 }" />

빈 값을 null로 원하는 경우 nullable를 사용하고, 없는 값에 undefined를 선호하는 경우 optional를 사용합니다.

Form 구성 요소 변경

Form 구성 요소는 v4에서 향상된 상태 관리 및 중첩된 양식 처리 기능을 제공합니다. 다음은 주의해야 할 주요 변경 사항입니다.

  1. Schema **transformations는 @submit data에만 적용되며 더 이상 폼의 상태를 변경하지 않습니다.이는 더 나은 예측 가능성을 제공하고 예기치 않은 상태 돌연변이를 방지합니다.
  2. Nested 양식은 nested prop를 사용하여 explicitly를 활성화해야 합니다. 이렇게 하면 구성 요소 동작이 보다 명확하게 만들어지고 실수로 중첩된 양식 생성을 방지할 수 있습니다.
  3. Nested 폼은 name prop (UFormField와 유사)을 제공하고 부모 폼에서 자동으로 상태를 상속합니다.
<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>

사용되지 않는 유틸리티 제거

이전에 Nuxt UI Pro에서 사용할 수 있었던 일부 **Nuxt 콘텐츠 활용 **는 v4에서 removed입니다.

  • findPageBreadcrumb 파일
  • findPageHeadline 파일

이제 Nuxt Content에 의해 완전히 제공됩니다. 가져오기 및 사용 방법을 적절히 업데이트하십시오.

- 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 마이그레이션(옵션)

이 섹션은 AI SDK 및 채팅 구성 요소(ChatMessage, ChatMessages, ChatPrompt, ChatPromptSubmit, ChatPalette)를 사용하는 경우에만 적용됩니다. AI 기능을 사용하지 않는 경우에는 이 섹션을 건너뛸 수도 있습니다.

  1. xpackage.json에서 @ai-sdk/vue 및 ai 종속성을 업데이트하고 Comark를 추가합니다 (AI 응답을 스트리밍 Markdown으로 렌더링하기 위해 @nuxtjs/mdc를 대체):
{
  "dependencies": {
-   "@ai-sdk/vue": "^1.2.x",
+   "@ai-sdk/vue": "^4.0.x",
-   "ai": "^4.3.x",
+   "ai": "^7.0.x",
+   "@comark/nuxt": "latest"
  }
}

@comark/nuxt를 모듈에 추가하십시오.

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. xuseChat 컴포블 API가 변경되었습니다: input 및 handleSubmit는 sendMessage를 선호하여 제거되었으며, messages는 이제 직접 설정한 참조입니다:
<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. Messages는 이제 content 대신 parts를 사용합니다.
// 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. Some 메서드의 이름이 변경되었습니다.
// Regenerate the last message
- reload()
+ regenerate()
  1. x<MDC>를 <Markdown>로 대체하여 파트 기반 렌더링을 수행합니다. Markdown 구성 요소는 Markdown 스트리밍을 위해 특별히 제작되었으며 AI에서 토큰이 도착하면 토큰을 점진적으로 렌더링합니다. AI SDK 도우미 및 @nuxt/ui/utils/ai의 isPartStreaming 유틸리티를 사용합니다.
shiki 플러그인을 사용하는 경우 다크 모드 지원을 위해 스타일시트에 다음 CSS를 추가합니다.
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>
AI SDK 변경 사항에 대한 자세한 내용은 **official AI SDK 마이그레이션 지침 **를 참조하십시오.
자세한 마이그레이션 참조를 위해 AI SDK v7 업그레이드 PR의 변경 사항을 확인하십시오.