v 4への移行
Nuxt UI v4は大きなマイルストーンとなりました。** Nuxt UIとNuxt UI Proは、完全にオープンソースで無料のライブラリ**に統合されました。125以上のプロダクション対応コンポーネントにアクセスでき、すべて@nuxt/uiパッケージで利用できます。
このガイドでは、アプリケーションをv 3からv 4に移行するためのステップバイステップの手順を説明します。
プロジェクトの移行
Nuxt UI Proから
@nuxt/ui-pro``@nuxt/ui``@nuxt/ui-proを@@に置き換えてください。
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
@nuxt/ui-pro``@nuxt/ui``nuxt.config.tsに置き換えてください。
export default defineNuxtConfig({
modules: [
- '@nuxt/ui-pro',
+ '@nuxt/ui'
]
})
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'
}
}
})
]
})
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',
- }
- }
- }
})
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";
- インポートの
@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>
Renamed PageMarquee
PageMarqueeコンポーネントは、Marqueeに改名されました。
<template>
- <UPageMarquee :items="items" />
+ <UMarquee :items="items" />
</template>
削除された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[InputNumber](/docs/components/input-number PH27 Textareaで使用されるmodelModifiers``modelModifiers``modelModifiers PH2222212121
nullify修飾子がnullableに改名されました(空/空白値をnullに変換します)。- 新しい
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コンポーネントはv4で改善され、状態管理とネストされたフォーム処理が改善されました。注意すべき主な変更点は次のとおりです。
- Schema 変換は
@submitdata **にのみ適用され、フォームの状態を変更しなくなります。これにより予測可能性が向上し、予期しない状態の変異を防ぎます。 - ネストされたフォームは、
nestedpropを使用して明示的にを有効にする必要があります。これにより、コンポーネントの動作がより明確になり、偶発的なネストされたフォームの作成を防ぎます。 - ネストされたフォームは、
namepropUFormFieldに似ていますを提供する必要があり、自動的に親フォームから状態を継承します。
<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で削除されました。
findPageBreadcrumbfindPageHeadline
これらは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機能を使用していない場合は、このセクションをスキップしてください。
package.jsonの@ai-sdk/vueとaiの依存関係を更新し、 Comark を追加しますストリーミングMarkdownとしてAIレスポンスをレンダリングするために@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"
}
}
useChat構成可能なAPIが変更されました。inputとhandleSubmitは削除され、sendMessageに置き換えられました。messagesは直接設定するrefになりました。
<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>
- メッセージが
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>
- いくつかのメソッドが名前変更されました
// Regenerate the last message
- reload()
+ regenerate()
<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>