nuxt-production

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Nuxt 4 Production Guide

Nuxt 4 生产环境指南

Hydration, performance, testing, deployment, and migration patterns.
涵盖Hydration、性能优化、测试、部署与迁移方案。

What's New in Nuxt 4

Nuxt 4 新特性

v4.2 Features (Latest)

v4.2 新特性(最新版)

1. Abort Control for Data Fetching
typescript
const controller = ref<AbortController>()

const { data } = await useAsyncData(
  'users',
  () => $fetch('/api/users', { signal: controller.value?.signal })
)

const abortRequest = () => {
  controller.value?.abort()
  controller.value = new AbortController()
}
2. Async Data Handler Extraction
  • 39% smaller client bundles
  • Data fetching logic extracted to server chunks
  • Automatic optimization (no config needed)
3. Enhanced Error Handling
  • Dual error display: custom error page + technical overlay
  • Better error messages in development
1. 数据请求的中止控制
typescript
const controller = ref<AbortController>()

const { data } = await useAsyncData(
  'users',
  () => $fetch('/api/users', { signal: controller.value?.signal })
)

const abortRequest = () => {
  controller.value?.abort()
  controller.value = new AbortController()
}
2. 异步数据处理逻辑提取
  • 客户端包体积减小39%
  • 数据请求逻辑提取至服务端代码块
  • 自动优化(无需配置)
3. 增强的错误处理
  • 双重错误展示:自定义错误页面 + 技术信息浮层
  • 开发环境下提供更清晰的错误提示

v4.1 Features

v4.1 新特性

1. Enhanced Chunk Stability
  • Import maps prevent cascading hash changes
  • Better long-term caching
2. Lazy Hydration
vue
<script setup>
const LazyComponent = defineLazyHydrationComponent(() =>
  import('./HeavyComponent.vue')
)
</script>
1. 增强的代码块稳定性
  • 导入映射防止哈希值连锁变更
  • 提升长期缓存效果
2. 延迟Hydration
vue
<script setup>
const LazyComponent = defineLazyHydrationComponent(() =>
  import('./HeavyComponent.vue')
)
</script>

Breaking Changes from v3

与v3相比的破坏性变更

Changev3v4
Source directoryRoot
app/
Data reactivityDeepShallow (default)
Default values
null
undefined
Route middlewareClientServer
App manifestOpt-inDefault
变更项v3v4
源码目录根目录
app/
数据响应性深度响应默认浅响应
默认值
null
undefined
路由中间件客户端服务端
应用清单可选启用默认启用

When to Load References

何时加载参考文档

Load
references/hydration.md
when:
  • Debugging "Hydration node mismatch" errors
  • Implementing ClientOnly components
  • Fixing non-deterministic rendering issues
  • Understanding SSR vs client rendering
Load
references/performance.md
when:
  • Optimizing Core Web Vitals scores
  • Implementing lazy loading and code splitting
  • Configuring caching strategies
  • Reducing bundle size
Load
references/testing-vitest.md
when:
  • Writing component tests with @nuxt/test-utils
  • Testing composables with Nuxt context
  • Mocking Nuxt APIs (useFetch, useRoute)
  • Setting up Vitest configuration
Load
references/deployment-cloudflare.md
when:
  • Deploying to Cloudflare Pages or Workers
  • Configuring wrangler.toml
  • Setting up NuxtHub integration
  • Working with D1, KV, R2 bindings
加载
references/hydration.md
的场景:
  • 调试「Hydration节点不匹配」错误
  • 实现ClientOnly组件
  • 修复非确定性渲染问题
  • 理解SSR与客户端渲染的差异
加载
references/performance.md
的场景:
  • 优化Core Web Vitals评分
  • 实现懒加载与代码分割
  • 配置缓存策略
  • 减小包体积
加载
references/testing-vitest.md
的场景:
  • 使用@nuxt/test-utils编写组件测试
  • 测试带有Nuxt上下文的组合式函数
  • 模拟Nuxt API(useFetch、useRoute)
  • 配置Vitest环境
加载
references/deployment-cloudflare.md
的场景:
  • 部署至Cloudflare Pages或Workers
  • 配置wrangler.toml
  • 集成NuxtHub
  • 使用D1、KV、R2绑定

Hydration Best Practices

Hydration 最佳实践

What Causes Hydration Mismatches

Hydration不匹配的原因

CauseExampleFix
Non-deterministic values
Math.random()
Use
useState
Browser APIs on server
window.innerWidth
Use
onMounted
Date/time on server
new Date()
Use
useState
or
ClientOnly
Third-party scriptsAnalyticsUse
ClientOnly
原因示例修复方案
非确定性值
Math.random()
使用
useState
服务端使用浏览器API
window.innerWidth
使用
onMounted
服务端生成日期/时间
new Date()
使用
useState
ClientOnly
第三方脚本分析脚本使用
ClientOnly

Fix Patterns

修复方案示例

Non-deterministic Values:
vue
<!-- WRONG -->
<script setup>
const id = Math.random()
</script>

<!-- CORRECT -->
<script setup>
const id = useState('random-id', () => Math.random())
</script>
Browser APIs:
vue
<!-- WRONG -->
<script setup>
const width = window.innerWidth  // Crashes on server!
</script>

<!-- CORRECT -->
<script setup>
const width = ref(0)
onMounted(() => {
  width.value = window.innerWidth
})
</script>
ClientOnly Component:
vue
<template>
  <!-- Wrap client-only content -->
  <ClientOnly>
    <MyMapComponent />
    <template #fallback>
      <div class="skeleton">Loading map...</div>
    </template>
  </ClientOnly>
</template>
Conditional Rendering:
vue
<script setup>
const showWidget = ref(false)

onMounted(() => {
  // Only show after hydration
  showWidget.value = true
})
</script>

<template>
  <AnalyticsWidget v-if="showWidget" />
</template>
非确定性值:
vue
<!-- WRONG -->
<script setup>
const id = Math.random()
</script>

<!-- CORRECT -->
<script setup>
const id = useState('random-id', () => Math.random())
</script>
浏览器API:
vue
<!-- WRONG -->
<script setup>
const width = window.innerWidth  // Crashes on server!
</script>

<!-- CORRECT -->
<script setup>
const width = ref(0)
onMounted(() => {
  width.value = window.innerWidth
})
</script>
ClientOnly组件:
vue
<template>
  <!-- Wrap client-only content -->
  <ClientOnly>
    <MyMapComponent />
    <template #fallback>
      <div class="skeleton">Loading map...</div>
    </template>
  </ClientOnly>
</template>
条件渲染:
vue
<script setup>
const showWidget = ref(false)

onMounted(() => {
  // Only show after hydration
  showWidget.value = true
})
</script>

<template>
  <AnalyticsWidget v-if="showWidget" />
</template>

Performance Optimization

性能优化

Lazy Loading Components

组件懒加载

vue
<script setup>
// Lazy load heavy components
const HeavyChart = defineAsyncComponent(() =>
  import('~/components/HeavyChart.vue')
)

// With loading/error states
const HeavyChart = defineAsyncComponent({
  loader: () => import('~/components/HeavyChart.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorFallback,
  delay: 200,
  timeout: 10000
})
</script>

<template>
  <Suspense>
    <HeavyChart :data="chartData" />
    <template #fallback>
      <LoadingSpinner />
    </template>
  </Suspense>
</template>
vue
<script setup>
// Lazy load heavy components
const HeavyChart = defineAsyncComponent(() =>
  import('~/components/HeavyChart.vue')
)

// With loading/error states
const HeavyChart = defineAsyncComponent({
  loader: () => import('~/components/HeavyChart.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorFallback,
  delay: 200,
  timeout: 10000
})
</script>

<template>
  <Suspense>
    <HeavyChart :data="chartData" />
    <template #fallback>
      <LoadingSpinner />
    </template>
  </Suspense>
</template>

Lazy Hydration

延迟Hydration

vue
<script setup>
// Hydrate when visible in viewport
const LazyComponent = defineLazyHydrationComponent(
  () => import('./HeavyComponent.vue'),
  { hydrate: 'visible' }
)

// Hydrate on user interaction
const InteractiveComponent = defineLazyHydrationComponent(
  () => import('./InteractiveComponent.vue'),
  { hydrate: 'interaction' }
)

// Hydrate when browser is idle
const IdleComponent = defineLazyHydrationComponent(
  () => import('./IdleComponent.vue'),
  { hydrate: 'idle' }
)
</script>
vue
<script setup>
// Hydrate when visible in viewport
const LazyComponent = defineLazyHydrationComponent(
  () => import('./HeavyComponent.vue'),
  { hydrate: 'visible' }
)

// Hydrate on user interaction
const InteractiveComponent = defineLazyHydrationComponent(
  () => import('./InteractiveComponent.vue'),
  { hydrate: 'interaction' }
)

// Hydrate when browser is idle
const IdleComponent = defineLazyHydrationComponent(
  () => import('./IdleComponent.vue'),
  { hydrate: 'idle' }
)
</script>

Route Caching

路由缓存

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Static pages (prerendered at build)
    '/': { prerender: true },
    '/about': { prerender: true },

    // SWR caching (1 hour)
    '/blog/**': { swr: 3600 },

    // ISR (regenerate every hour)
    '/products/**': { isr: 3600 },

    // SPA mode (no SSR)
    '/dashboard/**': { ssr: false },

    // Static with CDN caching
    '/static/**': {
      headers: { 'Cache-Control': 'public, max-age=31536000' }
    }
  }
})
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Static pages (prerendered at build)
    '/': { prerender: true },
    '/about': { prerender: true },

    // SWR caching (1 hour)
    '/blog/**': { swr: 3600 },

    // ISR (regenerate every hour)
    '/products/**': { isr: 3600 },

    // SPA mode (no SSR)
    '/dashboard/**': { ssr: false },

    // Static with CDN caching
    '/static/**': {
      headers: { 'Cache-Control': 'public, max-age=31536000' }
    }
  }
})

Image Optimization

图片优化

vue
<template>
  <!-- Automatic optimization with NuxtImg -->
  <NuxtImg
    src="/images/hero.jpg"
    alt="Hero image"
    width="800"
    height="400"
    loading="lazy"
    placeholder
    format="webp"
  />

  <!-- Responsive images -->
  <NuxtPicture
    src="/images/product.jpg"
    alt="Product"
    sizes="sm:100vw md:50vw lg:400px"
    :modifiers="{ quality: 80 }"
  />
</template>
vue
<template>
  <!-- Automatic optimization with NuxtImg -->
  <NuxtImg
    src="/images/hero.jpg"
    alt="Hero image"
    width="800"
    height="400"
    loading="lazy"
    placeholder
    format="webp"
  />

  <!-- Responsive images -->
  <NuxtPicture
    src="/images/product.jpg"
    alt="Product"
    sizes="sm:100vw md:50vw lg:400px"
    :modifiers="{ quality: 80 }"
  />
</template>

Testing with Vitest

使用Vitest进行测试

Setup

环境搭建

bash
bun add -d @nuxt/test-utils vitest @vue/test-utils happy-dom
typescript
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
  test: {
    environment: 'nuxt',
    environmentOptions: {
      nuxt: {
        domEnvironment: 'happy-dom'
      }
    }
  }
})
bash
bun add -d @nuxt/test-utils vitest @vue/test-utils happy-dom
typescript
// vitest.config.ts
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
  test: {
    environment: 'nuxt',
    environmentOptions: {
      nuxt: {
        domEnvironment: 'happy-dom'
      }
    }
  }
})

Component Testing

组件测试

typescript
// tests/components/UserCard.test.ts
import { describe, it, expect } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import UserCard from '~/components/UserCard.vue'

describe('UserCard', () => {
  it('renders user name', async () => {
    const wrapper = await mountSuspended(UserCard, {
      props: {
        user: { id: 1, name: 'John Doe', email: 'john@example.com' }
      }
    })

    expect(wrapper.text()).toContain('John Doe')
    expect(wrapper.text()).toContain('john@example.com')
  })

  it('emits delete event', async () => {
    const wrapper = await mountSuspended(UserCard, {
      props: { user: { id: 1, name: 'John' } }
    })

    await wrapper.find('[data-test="delete-btn"]').trigger('click')

    expect(wrapper.emitted('delete')).toHaveLength(1)
    expect(wrapper.emitted('delete')[0]).toEqual([1])
  })
})
typescript
// tests/components/UserCard.test.ts
import { describe, it, expect } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import UserCard from '~/components/UserCard.vue'

describe('UserCard', () => {
  it('renders user name', async () => {
    const wrapper = await mountSuspended(UserCard, {
      props: {
        user: { id: 1, name: 'John Doe', email: 'john@example.com' }
      }
    })

    expect(wrapper.text()).toContain('John Doe')
    expect(wrapper.text()).toContain('john@example.com')
  })

  it('emits delete event', async () => {
    const wrapper = await mountSuspended(UserCard, {
      props: { user: { id: 1, name: 'John' } }
    })

    await wrapper.find('[data-test="delete-btn"]').trigger('click')

    expect(wrapper.emitted('delete')).toHaveLength(1)
    expect(wrapper.emitted('delete')[0]).toEqual([1])
  })
})

Mocking Composables

模拟组合式函数

typescript
// tests/components/Dashboard.test.ts
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import Dashboard from '~/pages/dashboard.vue'

// Mock useFetch
mockNuxtImport('useFetch', () => {
  return () => ({
    data: ref({ users: [{ id: 1, name: 'John' }] }),
    pending: ref(false),
    error: ref(null)
  })
})

describe('Dashboard', () => {
  it('displays users from API', async () => {
    const wrapper = await mountSuspended(Dashboard)

    expect(wrapper.text()).toContain('John')
  })
})
typescript
// tests/components/Dashboard.test.ts
import { describe, it, expect, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import Dashboard from '~/pages/dashboard.vue'

// Mock useFetch
mockNuxtImport('useFetch', () => {
  return () => ({
    data: ref({ users: [{ id: 1, name: 'John' }] }),
    pending: ref(false),
    error: ref(null)
  })
})

describe('Dashboard', () => {
  it('displays users from API', async () => {
    const wrapper = await mountSuspended(Dashboard)

    expect(wrapper.text()).toContain('John')
  })
})

Testing Server Routes

测试服务端路由

typescript
// tests/api/users.test.ts
import { describe, it, expect } from 'vitest'
import { $fetch, setup } from '@nuxt/test-utils/e2e'

describe('API: /api/users', async () => {
  await setup({ server: true })

  it('returns users list', async () => {
    const users = await $fetch('/api/users')

    expect(users).toHaveProperty('users')
    expect(Array.isArray(users.users)).toBe(true)
  })

  it('creates a new user', async () => {
    const result = await $fetch('/api/users', {
      method: 'POST',
      body: { name: 'Jane', email: 'jane@example.com' }
    })

    expect(result.user.name).toBe('Jane')
  })
})
typescript
// tests/api/users.test.ts
import { describe, it, expect } from 'vitest'
import { $fetch, setup } from '@nuxt/test-utils/e2e'

describe('API: /api/users', async () => {
  await setup({ server: true })

  it('returns users list', async () => {
    const users = await $fetch('/api/users')

    expect(users).toHaveProperty('users')
    expect(Array.isArray(users.users)).toBe(true)
  })

  it('creates a new user', async () => {
    const result = await $fetch('/api/users', {
      method: 'POST',
      body: { name: 'Jane', email: 'jane@example.com' }
    })

    expect(result.user.name).toBe('Jane')
  })
})

Deployment

部署

Cloudflare Pages (Recommended)

Cloudflare Pages(推荐)

bash
undefined
bash
undefined

Build and deploy

Build and deploy

bun run build bunx wrangler pages deploy .output/public

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-pages'
  }
})
bun run build bunx wrangler pages deploy .output/public

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-pages'
  }
})

Cloudflare Workers

Cloudflare Workers

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-module'
  }
})
toml
undefined
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-module'
  }
})
toml
undefined

wrangler.toml

wrangler.toml

name = "my-nuxt-app" compatibility_date = "2025-01-01" compatibility_flags = ["nodejs_compat"]
[[d1_databases]] binding = "DB" database_name = "my-database" database_id = "xxx-xxx-xxx"
[[kv_namespaces]] binding = "KV" id = "xxx-xxx-xxx"
undefined
name = "my-nuxt-app" compatibility_date = "2025-01-01" compatibility_flags = ["nodejs_compat"]
[[d1_databases]] binding = "DB" database_name = "my-database" database_id = "xxx-xxx-xxx"
[[kv_namespaces]] binding = "KV" id = "xxx-xxx-xxx"
undefined

Vercel

Vercel

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'vercel'
  }
})
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'vercel'
  }
})

Netlify

Netlify

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'netlify'
  }
})
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'netlify'
  }
})

NuxtHub (Cloudflare All-in-One)

NuxtHub(Cloudflare一站式方案)

bash
bun add @nuxthub/core
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],

  hub: {
    database: true,  // D1
    kv: true,        // KV
    blob: true,      // R2
    cache: true      // Cache API
  }
})
typescript
// Usage in server routes
export default defineEventHandler(async (event) => {
  const db = hubDatabase()
  const kv = hubKV()
  const blob = hubBlob()

  // Use like regular Cloudflare bindings
  const users = await db.prepare('SELECT * FROM users').all()
})
bash
bun add @nuxthub/core
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],

  hub: {
    database: true,  // D1
    kv: true,        // KV
    blob: true,      // R2
    cache: true      // Cache API
  }
})
typescript
// Usage in server routes
export default defineEventHandler(async (event) => {
  const db = hubDatabase()
  const kv = hubKV()
  const blob = hubBlob()

  // Use like regular Cloudflare bindings
  const users = await db.prepare('SELECT * FROM users').all()
})

Environment Variables

环境变量

bash
undefined
bash
undefined

.env (development)

.env (development)

API_SECRET=dev-secret DATABASE_URL=http://localhost:8787
API_SECRET=dev-secret DATABASE_URL=http://localhost:8787

Production (Cloudflare)

Production (Cloudflare)

wrangler secret put API_SECRET wrangler secret put DATABASE_URL
wrangler secret put API_SECRET wrangler secret put DATABASE_URL

Production (Vercel/Netlify)

Production (Vercel/Netlify)

Set in dashboard or CLI

Set in dashboard or CLI

undefined
undefined

Migration from Nuxt 3

从Nuxt 3迁移

Step 1: Update package.json

步骤1:更新package.json

json
{
  "devDependencies": {
    "nuxt": "^4.0.0"
  }
}
json
{
  "devDependencies": {
    "nuxt": "^4.0.0"
  }
}

Step 2: Enable Compatibility Mode

步骤2:启用兼容模式

typescript
// nuxt.config.ts
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4
  }
})
typescript
// nuxt.config.ts
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4
  }
})

Step 3: Move Files to app/

步骤3:将文件移动至app/目录

bash
undefined
bash
undefined

Create app directory

Create app directory

mkdir app
mkdir app

Move files

Move files

mv components app/ mv composables app/ mv pages app/ mv layouts app/ mv middleware app/ mv plugins app/ mv assets app/ mv app.vue app/ mv error.vue app/
undefined
mv components app/ mv composables app/ mv pages app/ mv layouts app/ mv middleware app/ mv plugins app/ mv assets app/ mv app.vue app/ mv error.vue app/
undefined

Step 4: Fix Shallow Reactivity

步骤4:修复浅响应性问题

typescript
// If mutating data.value properties:
const { data } = await useFetch('/api/user', {
  deep: true  // Enable deep reactivity
})

// Or replace entire value
data.value = { ...data.value, name: 'New Name' }
typescript
// If mutating data.value properties:
const { data } = await useFetch('/api/user', {
  deep: true  // Enable deep reactivity
})

// Or replace entire value
data.value = { ...data.value, name: 'New Name' }

Step 5: Update Default Values

步骤5:更新默认值检查

typescript
// v3: data.value is null
// v4: data.value is undefined

// Update null checks
if (data.value === null) // v3
if (!data.value)         // v4 (works for both)
typescript
// v3: data.value is null
// v4: data.value is undefined

// Update null checks
if (data.value === null) // v3
if (!data.value)         // v4 (works for both)

Common Anti-Patterns

常见反模式

Client-Only Code on Server

服务端使用客户端专属代码

typescript
// WRONG
const width = window.innerWidth

// CORRECT
if (import.meta.client) {
  const width = window.innerWidth
}

// Or use onMounted
onMounted(() => {
  const width = window.innerWidth
})
typescript
// WRONG
const width = window.innerWidth

// CORRECT
if (import.meta.client) {
  const width = window.innerWidth
}

// Or use onMounted
onMounted(() => {
  const width = window.innerWidth
})

Non-Deterministic SSR

非确定性SSR

typescript
// WRONG - Different on server vs client
const id = Math.random()
const time = Date.now()

// CORRECT - Use useState for consistency
const id = useState('id', () => Math.random())
const time = useState('time', () => Date.now())
typescript
// WRONG - Different on server vs client
const id = Math.random()
const time = Date.now()

// CORRECT - Use useState for consistency
const id = useState('id', () => Math.random())
const time = useState('time', () => Date.now())

Missing Suspense for Async Components

异步组件未使用Suspense包裹

vue
<!-- WRONG -->
<AsyncComponent />

<!-- CORRECT -->
<Suspense>
  <AsyncComponent />
  <template #fallback>
    <LoadingSpinner />
  </template>
</Suspense>
vue
<!-- WRONG -->
<AsyncComponent />

<!-- CORRECT -->
<Suspense>
  <AsyncComponent />
  <template #fallback>
    <LoadingSpinner />
  </template>
</Suspense>

Troubleshooting

故障排查

Hydration Mismatch:
  • Check for
    window
    ,
    document
    ,
    localStorage
    usage
  • Wrap in
    ClientOnly
    or use
    onMounted
  • Look for
    Math.random()
    ,
    Date.now()
    ,
    crypto.randomUUID()
Build Errors:
bash
rm -rf .nuxt .output node_modules/.vite && bun install
Deployment Fails:
  • Check
    nitro.preset
    matches target
  • Verify environment variables are set
  • Check wrangler.toml bindings match code
Tests Failing:
  • Ensure
    @nuxt/test-utils
    is installed
  • Check vitest.config.ts has
    environment: 'nuxt'
  • Use
    mountSuspended
    for async components
Hydration不匹配:
  • 检查是否使用了
    window
    document
    localStorage
  • 使用
    ClientOnly
    包裹或
    onMounted
    钩子
  • 排查是否使用了
    Math.random()
    Date.now()
    crypto.randomUUID()
构建错误:
bash
rm -rf .nuxt .output node_modules/.vite && bun install
部署失败:
  • 检查
    nitro.preset
    是否与目标平台匹配
  • 验证环境变量是否已设置
  • 检查wrangler.toml中的绑定是否与代码一致
测试失败:
  • 确保已安装
    @nuxt/test-utils
  • 检查vitest.config.ts中是否设置了
    environment: 'nuxt'
  • 异步组件使用
    mountSuspended
    挂载

Related Skills

相关技能

  • nuxt-core: Project setup, routing, configuration
  • nuxt-data: Composables, data fetching, state
  • nuxt-server: Server routes, API patterns
  • cloudflare-d1: D1 database patterns

Version: 4.0.0 | Last Updated: 2025-12-28 | License: MIT
  • nuxt-core: 项目搭建、路由、配置
  • nuxt-data: 组合式函数、数据请求、状态管理
  • nuxt-server: 服务端路由、API方案
  • cloudflare-d1: D1数据库方案

版本: 4.0.0 | 最后更新: 2025-12-28 | 许可证: MIT