v4로 마이그레이션
Nuxt UI v4는 중요한 이정표를 표시합니다. **Nuxt UI와 Nuxt UI Pro는 이제 완전히 오픈 소스 및 무료 라이브러리 **로 통합되었습니다. 이제 @nuxt/ui 패키지에서 사용할 수 있는 125+ 프로덕션 준비 구성 요소에 액세스할 수 있습니다.
이 가이드에서는 애플리케이션을 v3에서 v4로 마이그레이션하는 단계별 지침을 제공합니다.
프로젝트 마이그레이션
Nuxt UI Pro 에서
- xx
@nuxt/ui-pro를package.json에서@nuxt/ui로 바꿉니다.
pnpm remove @nuxt/ui-pro
pnpm add @nuxt/ui tailwindcss
yarn remove @nuxt/ui-pro
yarn add @nuxt/ui tailwindcss
npm uninstall @nuxt/ui-pro
npm install @nuxt/ui tailwindcss
bun remove @nuxt/ui-pro
bun add @nuxt/ui tailwindcss
- xx
@nuxt/ui-pro를nuxt.config.ts에서@nuxt/ui로 대체합니다.
export default defineNuxtConfig({
modules: [
- '@nuxt/ui-pro',
+ '@nuxt/ui'
]
})
- xx
vite.config.ts에서@nuxt/ui-pro를@nuxt/ui로 바꿉니다.
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'
}
}
})
]
})
- x
app.config.ts에서uiPro대신ui키를 사용합니다.
export default defineAppConfig({
ui: {
colors: {
primary: 'green',
neutral: 'slate'
},
+ pageCard: {
+ slots: {
+ root: 'rounded-xl',
+ }
+ }
},
- uiPro: {
- pageCard: {
- slots: {
- root: 'rounded-xl',
- }
- }
- }
})
- x
vite.config.ts에서uiPro대신ui키를 사용하십시오.
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
colors: {
primary: 'green',
neutral: 'slate'
},
+ pageCard: {
+ slots: {
+ root: 'rounded-xl',
+ }
+ }
},
- uiPro: {
- pageCard: {
- slots: {
- root: 'rounded-xl',
- }
- }
- }
})
]
})
- CSS에서
@nuxt/ui-pro를@nuxt/ui로 바꿉니다.
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
@source 지시어를 새 디렉토리 구조에 맞게 업데이트해야 합니다.@import "tailwindcss";
@import "@nuxt/ui";
- @source "../../content/**/*";
+ @source "../../../content/**/*";
@import "tailwindcss";
- @import "@nuxt/ui-pro";
+ @import "@nuxt/ui";
- import에서
@nuxt/ui-pro를@nuxt/ui로 바꿉니다.
- import type { BannerProps } from '@nuxt/ui-pro'
+ import type { BannerProps } from '@nuxt/ui'
Nuxt UI에서
- Nuxt UI v3에서 업그레이드하는 경우 v4로 업데이트하기만 하면 됩니다.
pnpm add @nuxt/ui tailwindcss
yarn add @nuxt/ui tailwindcss
npm install @nuxt/ui tailwindcss
bun 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에서 변경되었습니다.
- x
nullify수정자의 이름이nullable로 바뀌었습니다 (비어 있거나 빈 값을null로 변환). - 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에서 향상된 상태 관리 및 중첩된 양식 처리 기능을 제공합니다. 다음은 주의해야 할 주요 변경 사항입니다.
- Schema **transformations는
@submitdata에만 적용되며 더 이상 폼의 상태를 변경하지 않습니다.이는 더 나은 예측 가능성을 제공하고 예기치 않은 상태 돌연변이를 방지합니다. - Nested 양식은
nestedprop를 사용하여 explicitly를 활성화해야 합니다. 이렇게 하면 구성 요소 동작이 보다 명확하게 만들어지고 실수로 중첩된 양식 생성을 방지할 수 있습니다. - Nested 폼은
nameprop (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 기능을 사용하지 않는 경우에는 이 섹션을 건너뛸 수도 있습니다.
- x
package.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를 모듈에 추가하십시오.
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"
}
}
- x
useChat컴포블 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>
- 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>
- Some 메서드의 이름이 변경되었습니다.
// Regenerate the last message
- reload()
+ regenerate()
- x
<MDC>를<Markdown>로 대체하여 파트 기반 렌더링을 수행합니다.Markdown구성 요소는 Markdown 스트리밍을 위해 특별히 제작되었으며 AI에서 토큰이 도착하면 토큰을 점진적으로 렌더링합니다. AI SDK 도우미 및@nuxt/ui/utils/ai의isPartStreaming유틸리티를 사용합니다.
shiki 플러그인을 사용하는 경우 다크 모드 지원을 위해 스타일시트에 다음 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>