跳到正文
cccskills
免费在 GitHub 公开

nuxt-production

| Nuxt 5 production optimization: hydration, performance, testing with Vitest, deployment to Cloudflare/Vercel/Netlify, and migration from Nuxt 4. Use when: debugging hydration mismatches, optimizing performance and Core Web Vitals, writing tests with Vitest, deploying to Cloudflare Pages/Workers/Vercel/Netlify, or migrating from Nuxt 4 to Nuxt 5.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(7)

  • SKILL.md10.7 KB
  • references/deployment-cloudflare.md13.5 KB
  • references/hydration.md8.4 KB
  • references/performance.md11.8 KB
  • references/testing-vitest.md13.2 KB
  • templates/tests/components/BlogPost.test.ts1.2 KB
  • templates/wrangler.toml1.0 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

Nuxt 5 Production Guide

Hydration, performance, testing, deployment, and migration patterns.

What's New in Nuxt 5

v5 Key Changes

ChangeNuxt 4Nuxt 5
BundlerVite 6 (esbuild + Rollup)Vite 8 (Rolldown)
Server engineNitro v2Nitro v3 (h3 v2)
Server errorscreateError({statusCode})HTTPError({status})
Client-only placeholderEmpty <div>HTML comment node
callHookAlways returns PromiseMay return void
clearNuxtStateSets to undefinedResets to initial default
Page namesAuto-generatedNormalized to route names
JSX supportIncluded by defaultOptional (on-demand)
externalVueConfigurableRemoved (always mocked)

Client-Only Comment Placeholders (v5)

Client-only components (.client.vue files and createClientOnly() wrappers) now render an HTML comment on the server instead of an empty <div>. This fixes scoped styles hydration issues.

<!-- If you relied on the placeholder <div> for layout -->
<ClientOnly>
  <MyComponent />
  <template #fallback>
    <div class="placeholder" style="min-height: 200px"></div>
  </template>
</ClientOnly>

To revert to the old <div> behavior:

// nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    clientNodePlaceholder: false
  }
})

Non-Async callHook (v5)

callHook may now return void instead of always returning Promise. Always use await:

// WRONG
nuxtApp.callHook('my:hook', data).then(() => { ... })

// CORRECT
await nuxtApp.callHook('my:hook', data)

When to Load References

Load references/hydration.md when:

  • Debugging "Hydration node mismatch" errors
  • Implementing ClientOnly components
  • Fixing non-deterministic rendering issues

Load references/performance.md when:

  • Optimizing Core Web Vitals scores
  • Implementing lazy loading and code splitting
  • Reducing bundle size

Load references/testing-vitest.md when:

  • Writing component tests with @nuxt/test-utils
  • Testing composables with Nuxt context
  • Mocking Nuxt APIs

Load references/deployment-cloudflare.md when:

  • Deploying to Cloudflare Pages or Workers
  • Configuring wrangler.toml
  • Setting up NuxtHub integration

Hydration Best Practices

What Causes Hydration Mismatches

CauseExampleFix
Non-deterministic valuesMath.random()Use useState
Browser APIs on serverwindow.innerWidthUse onMounted
Date/time on servernew Date()Use useState or ClientOnly
Third-party scriptsAnalyticsUse ClientOnly

Fix Patterns

<!-- Non-deterministic values -->
<script setup>
const id = useState('random-id', () => Math.random())
</script>

<!-- Browser APIs -->
<script setup>
const width = ref(0)
onMounted(() => {
  width.value = window.innerWidth
})
</script>

<!-- ClientOnly component -->
<template>
  <ClientOnly>
    <MyMapComponent />
    <template #fallback>
      <div class="skeleton">Loading map...</div>
    </template>
  </ClientOnly>
</template>

Performance Optimization

Lazy Loading Components

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

Lazy Hydration

<script setup>
const LazyComponent = defineLazyHydrationComponent(
  'visible',
  () => import('./HeavyComponent.vue')
)

const InteractiveComponent = defineLazyHydrationComponent(
  'interaction',
  () => import('./InteractiveComponent.vue')
)

const IdleComponent = defineLazyHydrationComponent(
  'idle',
  () => import('./IdleComponent.vue')
)
</script>

Route Caching

export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },
    '/about': { prerender: true },
    '/blog/**': { swr: 3600 },
    '/products/**': { isr: 3600 },
    '/dashboard/**': { ssr: false },
    '/static/**': {
      headers: { 'Cache-Control': 'public, max-age=31536000' }
    }
  }
})

Image Optimization

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

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

Testing with Vitest

Setup

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

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

Component Testing

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')
  })
})

Mocking Composables

import { mockNuxtImport } from '@nuxt/test-utils/runtime'

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

Deployment

Cloudflare Pages (Recommended)

bun run build
bunx wrangler pages deploy .output/public
export default defineNuxtConfig({
  nitro: { preset: 'cloudflare_pages' }
})

Cloudflare Workers

export default defineNuxtConfig({
  nitro: { preset: 'cloudflare_module' }
})

Vercel / Netlify

// Vercel
export default defineNuxtConfig({
  nitro: { preset: 'vercel' }
})

// Netlify
export default defineNuxtConfig({
  nitro: { preset: 'netlify' }
})

NuxtHub (Cloudflare All-in-One)

bun add @nuxthub/core
export default defineNuxtConfig({
  modules: ['@nuxthub/core'],
  hub: {
    database: true,
    kv: true,
    blob: true,
    cache: true
  }
})

Migration from Nuxt 4

Step 1: Update package.json

{
  "devDependencies": {
    "nuxt": "^5.0.0"
  }
}

Step 2: Enable Compatibility Mode

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

Step 3: Update Server Error Handling

// Before (Nuxt 4)
import { createError } from 'h3'
throw createError({ statusCode: 404, statusMessage: 'Not Found' })

// After (Nuxt 5)
import { HTTPError } from 'nitro/h3'
throw new HTTPError({ status: 404, statusText: 'Not Found' })

Step 4: Update Server Event API

// Before (Nuxt 4)
const path = event.path
event.node.res.statusCode = 200
setResponseHeader(event, 'x-custom', 'value')
const config = useRuntimeConfig(event)

// After (Nuxt 5)
const path = event.url.pathname
event.res.status = 200
event.res.headers.set('x-custom', 'value')
const config = useRuntimeConfig()

Step 5: Update Vite Config

// Before (Nuxt 4)
export default defineNuxtConfig({
  vite: {
    build: {
      rollupOptions: { ... }
    }
  }
})

// After (Nuxt 5) - use rolldownOptions
export default defineNuxtConfig({
  vite: {
    build: {
      rolldownOptions: { ... }
    }
  }
})

Step 6: Update Route Rules

// Before
routeRules: {
  '/old': { redirect: { to: '/new', statusCode: 302 } }
}

// After
routeRules: {
  '/old': { redirect: { to: '/new', status: 302 } }
}

Step 7: Update Import Paths

// Before
import { defineEventHandler, getQuery } from 'h3'

// After
import { defineEventHandler, getQuery } from 'nitro/h3'
// Or rely on auto-imports (no import needed)

Step 8: Remove Deprecated Options

// Remove these from nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    externalVue: false,  // REMOVED - delete this
    viteEnvironmentApi: true,  // REMOVED - always enabled
  }
})

Step 9: Install JSX Plugin (If Needed)

# Only if your project uses .jsx/.tsx files
bun add -D @vitejs/plugin-vue-jsx

Step 10: Update callHook Usage

// Before
nuxtApp.callHook('my:hook', data).then(() => { ... })

// After
await nuxtApp.callHook('my:hook', data)

Common Anti-Patterns

Client-Only Code on Server

// 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

// WRONG
const id = Math.random()
const time = Date.now()

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

Troubleshooting

Hydration Mismatch:

  • Check for window, document, localStorage usage
  • Wrap in ClientOnly or use onMounted
  • Look for Math.random(), Date.now()
  • Check if relying on <div> placeholder for client-only components

Build Errors:

rm -rf .nuxt .output node_modules/.vite && bun install

Vite Plugin Warnings:

  • Migrate from extendViteConfig({ server }) to configEnvironment
  • Use applyToEnvironment instead of server: false / client: false

Rolldown Build Issues:

  • Replace rollupOptions with rolldownOptions
  • Replace vite.esbuild with vite.oxc
  • Check CJS interop changes in Vite 8

Related Skills

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

Version: 5.0.0 | Last Updated: 2026-03-30 | License: MIT

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

100+ animated React components (Aceternity UI) for Next.js with Tailwind. Use for hero sections, parallax, 3D effects, or encountering animation, shadcn CLI integration errors.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

Secure API authentication with JWT, OAuth 2.0, API keys. Use for authentication systems, third-party integrations, service-to-service communication, or encountering token management, security headers, auth flow errors.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

Creates comprehensive API changelogs documenting breaking changes, deprecations, and migration strategies for API consumers. Use when managing API versions, communicating breaking changes, or creating upgrade guides.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

Verifies API contracts between services using consumer-driven contracts, schema validation, and tools like Pact. Use when testing microservices communication, preventing breaking changes, or validating OpenAPI specifications.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

Implements standardized API error responses with proper status codes, logging, and user-friendly messages. Use when building production APIs, implementing error recovery patterns, or integrating error monitoring services.

中文简介正在准备中。当前显示原文说明。

secondsky/claude-skills2322026年10月20日 更新

查看 secondsky 的全部技能

报告此技能的问题