🚀 全新升级 - Nuxt4 AI企业级开发实战指南现已发布!

Nuxt 性能优化指南

深度解析 Nuxt 框架性能优化指南,从基础配置到高级优化策略,涵盖 SSR、SSG、ISR、资源优化、缓存策略、性能监控等核心技术,构建高性能 Web 应用

概述

在现代 Web 开发中,性能优化已成为决定应用成功的关键因素。据 Google 研究显示,页面加载时间超过 3 秒将导致 53% 的用户流失,而优化后的应用可以显著提升转化率和用户体验。Nuxt 框架基于 Vue.js 构建,提供了完整的性能优化工具链,从服务端渲染到客户端优化,从构建时优化到运行时性能调优。

本指南将深入探讨 Nuxt 性能优化的全链路实践,帮助开发者掌握从理论到实践的完整优化体系。

🎯 核心目标

  • 掌握 Nuxt 性能优化的全链路方法论和最佳实践
  • 深入理解渲染模式、缓存策略和资源优化的技术原理
  • 学会构建高效的监控体系和性能诊断方法
  • 掌握企业级应用的性能优化策略和架构设计

💡 技术架构体系

  • Nitro 引擎: 统一的服务端运行时和优化机制
  • Vite/Webpack: 现代化构建工具和打包优化
  • Vue 3: 组合式 API 和响应式系统优化
  • 边缘计算: CDN 和 Edge Runtime 性能提升
  • 智能缓存: 多层次缓存策略和缓存失效机制

第一部分:性能优化基础理论

Web 性能关键指标深入解析

现代 Web 性能评估基于 Core Web Vitals 和其他关键指标,了解这些指标对于制定有效的优化策略至关重要。

Core Web Vitals 指标详解

Largest Contentful Paint (LCP)

LCP(最大内容绘制)是衡量用户感知加载速度的核心指标,用于记录视窗内最大内容元素(如图像、视频、文本块)的渲染时间点。

关键要素解析:

  1. 内容类型:包括但不限于:
    • 图片/视频
    • 页面主标题(H1)
    • 关键信息横幅
    • 首屏产品卡片
  2. 测量标准
    • 元素必须可见且在视窗内
    • 内容需为实际渲染内容(非背景或占位符)
    • 元素尺寸需占视窗面积 30% 以上

技术原理:

  • 浏览器渲染引擎会持续追踪内容元素的尺寸和位置变化
  • 当布局稳定后(无后续 DOM 变更影响),记录最大元素的渲染时间
  • 测量时间点包含网络请求、资源解码、渲染管线执行等全链路耗时

优化关注点:

  • 消除渲染阻塞资源(Render-blocking Resources)
  • 优化关键渲染路径(Critical Rendering Path)
  • 确保文本内容使用正确的字体加载策略(FOIT/FOUT)
  • 优先保障首屏内容的 CSS 交付优化(Critical CSS)

优化目标

  • 目标值: ≤ 2.5 秒
  • 技术原理: 衡量页面主要内容的渲染时间
  • 优化策略: 服务端渲染、图像优化、关键资源预加载
// LCP 优化示例:关键资源预加载
export default defineNuxtConfig({
  app: {
    head: {
      link: [
        {
          rel: 'preload',
          href: '/images/hero-image.webp',
          as: 'image',
          fetchpriority: 'high'
        }
      ]
    }
  }
})

First Input Delay (FID) / Interaction to Next Paint (INP)

  • 目标值: FID ≤ 100ms, INP ≤ 200ms
  • 技术原理: 衡量用户交互响应速度
  • 优化策略: 代码分割、主线程优化、Web Workers
// 主线程优化:使用 Web Workers 处理计算密集型任务
// composables/useWebWorker.ts
export const useWebWorker = () => {
  const processData = async (data: any) => {
    if (process.client) {
      const worker = new Worker('/workers/data-processor.js')
      
      return new Promise((resolve) => {
        worker.postMessage(data)
        worker.onmessage = (e) => {
          resolve(e.data)
          worker.terminate()
        }
      })
    }
  }
  
  return { processData }
}

Cumulative Layout Shift (CLS)

  • 目标值: ≤ 0.1
  • 技术原理: 衡量视觉稳定性
  • 优化策略: 尺寸预定义、骨架屏、字体优化
<!-- CLS 优化:预定义图片尺寸 -->
<template>
  <div>
    <NuxtImg
      src="/images/product.jpg"
      width="400"
      height="300"
      :style="{ aspectRatio: '4/3' }"
      loading="lazy"
      placeholder
    />
  </div>
</template>

Nuxt 性能优化技术栈分析

Nitro 引擎核心机制

Nitro 是 Nuxt 3 的服务端引擎,提供了统一的服务端运行时环境和优化机制:

// nitro.config.ts - Nitro 优化配置
export default defineNitroConfig({
  // 预渲染配置
  prerender: {
    routes: ['/sitemap.xml'],
    crawlLinks: true
  },
  
  // 压缩配置
  compression: true,
  
  // 实验性功能
  experimental: {
    wasm: true
  },
  
  // 路由规则
  routeRules: {
    '/': { prerender: true },
    '/api/**': { headers: { 'cache-control': 's-maxage=60' } },
    '/admin/**': { ssr: false },
    '/blog/**': { isr: true }
  }
})

渲染模式性能对比分析

渲染模式首屏时间SEO 友好服务器负载缓存策略适用场景
SSR优秀动态内容网站、电商
SSG最快优秀静态博客、文档
SPA客户端管理后台
ISR优秀智能大型网站
混合渲染优化灵活可控分层企业应用

第二部分:构建时性能优化

代码分割和懒加载策略

自动代码分割机制

Nuxt 基于路由自动进行代码分割,但我们可以进一步优化:

// nuxt.config.ts - 高级代码分割配置
export default defineNuxtConfig({
  build: {
    splitChunks: {
      layouts: true,
      pages: true,
      commons: true
    }
  },
  
  // Vite 优化配置
  vite: {
    build: {
      rollupOptions: {
        output: {
          manualChunks(id) {
            // 第三方库分离
            if (id.includes('node_modules')) {
              if (id.includes('vue') || id.includes('@vue')) {
                return 'vue-vendor'
              }
              if (id.includes('lodash')) {
                return 'lodash'
              }
              return 'vendor'
            }
          }
        }
      }
    }
  }
})

组件级懒加载最佳实践

<!-- pages/products/index.vue -->
<template>
  <div>
    <ProductHeader />
    
    <!-- 延迟加载非关键组件 -->
    <ClientOnly>
      <LazyProductRecommendations />
      <template #fallback>
        <div class="skeleton-loader">
          <div class="skeleton-item" v-for="i in 4" :key="i" />
        </div>
      </template>
    </ClientOnly>
    
    <!-- 条件懒加载 -->
    <LazyProductReviews v-if="showReviews" />
  </div>
</template>

<script setup>
// 异步组件定义
const LazyProductRecommendations = defineAsyncComponent(() => 
  import('~/components/ProductRecommendations.vue')
)

const showReviews = ref(false)

// 延迟加载评论组件
onMounted(() => {
  setTimeout(() => {
    showReviews.value = true
  }, 2000)
})
</script>

动态导入优化策略

// composables/useModuleLoader.ts
export const useModuleLoader = () => {
  const loadModule = async <T>(modulePath: string): Promise<T> => {
    try {
      // 使用动态导入并添加预取提示
      const module = await import(/* webpackChunkName: "dynamic-module" */ modulePath)
      return module.default
    } catch (error) {
      console.error(`Failed to load module: ${modulePath}`, error)
      throw error
    }
  }
  
  const preloadModule = (modulePath: string) => {
    // 预加载模块以提升后续加载速度
    if (process.client) {
      const link = document.createElement('link')
      link.rel = 'modulepreload'
      link.href = modulePath
      document.head.appendChild(link)
    }
  }
  
  return { loadModule, preloadModule }
}

资源优化和压缩

图像优化全方位策略

// nuxt.config.ts - 图像优化配置
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  
  image: {
    // 图像格式优化
    formats: {
      avif: {
        quality: 80
      },
      webp: {
        quality: 85
      }
    },
    
    // 响应式图像配置
    screens: {
      xs: 320,
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1280,
      xxl: 1536
    },
    
    // 图像提供商配置
    providers: {
      cloudinary: {
        baseURL: 'https://res.cloudinary.com/your-cloud/image/fetch/'
      }
    },
    
    // 预设配置
    presets: {
      hero: {
        modifiers: {
          format: 'webp',
          quality: 90,
          width: 1200,
          height: 600
        }
      },
      thumbnail: {
        modifiers: {
          format: 'webp',
          quality: 80,
          width: 200,
          height: 200
        }
      }
    }
  }
})
<!-- 高性能图像组件 -->
<template>
  <div class="responsive-image-container">
    <NuxtPicture
      :src="imageSrc"
      :alt="imageAlt"
      :preset="imagePreset"
      :loading="imageLoading"
      :fetchpriority="fetchPriority"
      :sizes="responsiveSizes"
      @load="onImageLoad"
      @error="onImageError"
    />
  </div>
</template>

<script setup lang="ts">
interface Props {
  imageSrc: string
  imageAlt: string
  imagePreset?: 'hero' | 'thumbnail' | 'default'
  imageLoading?: 'lazy' | 'eager'
  fetchPriority?: 'high' | 'low' | 'auto'
  responsiveSizes?: string
}

const props = withDefaults(defineProps<Props>(), {
  imagePreset: 'default',
  imageLoading: 'lazy',
  fetchPriority: 'auto',
  responsiveSizes: '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
})

const onImageLoad = () => {
  // 图像加载完成后的处理
  console.log('Image loaded successfully')
}

const onImageError = () => {
  // 图像加载失败的处理
  console.error('Failed to load image')
}
</script>

字体优化和加载策略

// nuxt.config.ts - 字体优化配置
export default defineNuxtConfig({
  modules: ['@nuxtjs/google-fonts'],
  
  googleFonts: {
    families: {
      'Inter': [400, 500, 600, 700],
      'JetBrains Mono': [400, 500]
    },
    display: 'swap',
    preload: true,
    useStylesheet: true,
    download: true,
    base64: false
  },
  
  app: {
    head: {
      link: [
        // 字体预连接
        { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
        { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' }
      ]
    }
  }
})

CSS 优化和关键路径

// nuxt.config.ts - CSS 优化配置
export default defineNuxtConfig({
  css: [
    '~/assets/css/critical.css', // 关键 CSS
    '~/assets/css/main.css'
  ],
  
  build: {
    // CSS 提取和优化
    extractCSS: {
      ignoreOrder: true
    }
  },
  
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "~/assets/scss/variables.scss" as *;'
        }
      }
    }
  }
})
// assets/scss/critical.scss - 关键路径 CSS
// 首屏必需的样式
.layout-header {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 1000;
  height: 64px;
  background: white;
  border-bottom: 1px solid #e5e7eb;
}

.hero-section {
  padding-top: 64px;
  min-height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

// 骨架屏样式
.skeleton-loader {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

.skeleton-item {
  height: 200px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
  border-radius: 8px;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

Tree Shaking 和依赖优化

智能依赖分析和优化

// nuxt.config.ts - Tree Shaking 优化
export default defineNuxtConfig({
  build: {
    // 分析包大小
    analyze: process.env.ANALYZE === 'true',
    
    // 优化依赖
    optimization: {
      treeShake: true,
      minimize: true
    }
  },
  
  // 自动导入优化
  imports: {
    // 禁用全局导入,按需导入
    global: false,
    // 自定义导入
    imports: [
      { from: 'lodash-es', name: 'debounce', as: 'debounce' },
      { from: 'date-fns', name: 'format', as: 'formatDate' }
    ]
  }
})
// utils/optimized-imports.ts - 优化的导入策略
// 错误示例:导入整个库
// import _ from 'lodash'

// 正确示例:按需导入
import { debounce, throttle } from 'lodash-es'
import { format, addDays } from 'date-fns'

// 动态导入大型库
export const loadChartLibrary = async () => {
  const { Chart } = await import('chart.js/auto')
  return Chart
}

// 条件导入
export const loadDevTools = async () => {
  if (process.dev) {
    const { setupDevtoolsPlugin } = await import('@vue/devtools-api')
    return setupDevtoolsPlugin
  }
}

第三部分:运行时性能优化

服务端渲染优化

SSR 渲染优化策略

// server/api/performance/[...slug].ts
export default defineEventHandler(async (event) => {
  const start = Date.now()
  
  try {
    // 缓存检查
    const cached = await useStorage('redis').getItem(getRequestURL(event).pathname)
    if (cached) {
      setHeader(event, 'X-Cache', 'HIT')
      setHeader(event, 'X-Response-Time', `${Date.now() - start}ms`)
      return cached
    }
    
    // 数据获取优化
    const [userData, contentData] = await Promise.all([
      $fetch('/api/user'),
      $fetch('/api/content')
    ])
    
    const result = {
      user: userData,
      content: contentData,
      timestamp: Date.now()
    }
    
    // 设置缓存
    await useStorage('redis').setItem(
      getRequestURL(event).pathname, 
      result, 
      { ttl: 300 } // 5分钟缓存
    )
    
    setHeader(event, 'X-Cache', 'MISS')
    setHeader(event, 'X-Response-Time', `${Date.now() - start}ms`)
    
    return result
  } catch (error) {
    throw createError({
      statusCode: 500,
      statusMessage: 'Internal Server Error'
    })
  }
})

数据获取优化模式

<!-- pages/products/[id].vue -->
<template>
  <div>
    <ProductDetail :product="data.product" />
    <ProductReviews :reviews="data.reviews" />
    <ProductRecommendations :recommendations="data.recommendations" />
  </div>
</template>

<script setup>
// 并行数据获取
const { params } = useRoute()

const { data, error, pending } = await useLazyAsyncData(
  `product-${params.id}`,
  async () => {
    // 并行获取所有需要的数据
    const [product, reviews, recommendations] = await Promise.all([
      $fetch(`/api/products/${params.id}`),
      $fetch(`/api/products/${params.id}/reviews`),
      $fetch(`/api/products/${params.id}/recommendations`)
    ])
    
    return {
      product,
      reviews,
      recommendations
    }
  },
  {
    // 缓存配置
    server: true,
    client: true,
    default: () => ({
      product: null,
      reviews: [],
      recommendations: []
    })
  }
)

// SEO 优化
useHead({
  title: () => data.value?.product?.title || 'Product',
  meta: [
    {
      name: 'description',
      content: () => data.value?.product?.description || 'Product description'
    }
  ]
})
</script>

客户端性能优化

水合(Hydration)优化

<!-- components/OptimizedComponent.vue -->
<template>
  <div>
    <!-- 关键内容立即渲染 -->
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
    
    <!-- 非关键组件延迟水合 -->
    <ClientOnly>
      <InteractiveChart :data="chartData" />
      <template #fallback>
        <div class="chart-skeleton">Loading chart...</div>
      </template>
    </ClientOnly>
    
    <!-- 条件性组件 -->
    <LazyModal v-if="showModal" @close="showModal = false" />
  </div>
</template>

<script setup>
// 使用 ref 而不是 reactive 提升性能
const title = ref('')
const description = ref('')
const chartData = ref([])
const showModal = ref(false)

// 优化的数据获取
onMounted(async () => {
  // 分批加载数据
  const basicData = await $fetch('/api/basic-data')
  title.value = basicData.title
  description.value = basicData.description
  
  // 延迟加载图表数据
  setTimeout(async () => {
    chartData.value = await $fetch('/api/chart-data')
  }, 100)
})
</script>

状态管理优化

// stores/performance.ts
export const usePerformanceStore = defineStore('performance', () => {
  // 使用 Map 提升查找性能
  const cache = new Map<string, any>()
  const loadingStates = new Set<string>()
  
  // 防抖的数据获取
  const debouncedFetch = debounce(async (key: string, fetcher: Function) => {
    if (cache.has(key)) {
      return cache.get(key)
    }
    
    if (loadingStates.has(key)) {
      return new Promise(resolve => {
        const interval = setInterval(() => {
          if (cache.has(key)) {
            clearInterval(interval)
            resolve(cache.get(key))
          }
        }, 50)
      })
    }
    
    loadingStates.add(key)
    
    try {
      const result = await fetcher()
      cache.set(key, result)
      return result
    } finally {
      loadingStates.delete(key)
    }
  }, 100)
  
  // 内存管理
  const clearCache = () => {
    cache.clear()
    loadingStates.clear()
  }
  
  // 缓存大小限制
  const limitCacheSize = (maxSize: number = 50) => {
    if (cache.size > maxSize) {
      const keys = Array.from(cache.keys())
      const keysToDelete = keys.slice(0, cache.size - maxSize)
      keysToDelete.forEach(key => cache.delete(key))
    }
  }
  
  return {
    debouncedFetch,
    clearCache,
    limitCacheSize,
    getCacheSize: () => cache.size
  }
})

缓存策略深度优化

多层缓存架构设计

// utils/cache-manager.ts
interface CacheConfig {
  ttl?: number
  storage?: 'memory' | 'sessionStorage' | 'localStorage' | 'redis'
  namespace?: string
}

export class CacheManager {
  private memoryCache = new Map<string, { data: any; expires: number }>()
  private readonly defaultTTL = 300000 // 5分钟
  
  async get<T>(key: string, config?: CacheConfig): Promise<T | null> {
    const fullKey = this.getFullKey(key, config?.namespace)
    
    // 1. 检查内存缓存
    const memoryResult = this.getFromMemory<T>(fullKey)
    if (memoryResult !== null) return memoryResult
    
    // 2. 检查浏览器存储
    if (process.client && config?.storage) {
      const browserResult = this.getFromBrowser<T>(fullKey, config.storage)
      if (browserResult !== null) {
        // 回填内存缓存
        this.setToMemory(fullKey, browserResult, config?.ttl)
        return browserResult
      }
    }
    
    // 3. 检查服务端缓存 (Redis)
    if (process.server && config?.storage === 'redis') {
      const redisResult = await this.getFromRedis<T>(fullKey)
      if (redisResult !== null) return redisResult
    }
    
    return null
  }
  
  async set<T>(
    key: string, 
    data: T, 
    config?: CacheConfig
  ): Promise<void> {
    const fullKey = this.getFullKey(key, config?.namespace)
    const ttl = config?.ttl || this.defaultTTL
    
    // 设置内存缓存
    this.setToMemory(fullKey, data, ttl)
    
    // 设置浏览器存储
    if (process.client && config?.storage) {
      this.setBrowser(fullKey, data, config.storage, ttl)
    }
    
    // 设置服务端缓存
    if (process.server && config?.storage === 'redis') {
      await this.setRedis(fullKey, data, ttl)
    }
  }
  
  private getFromMemory<T>(key: string): T | null {
    const cached = this.memoryCache.get(key)
    if (cached && cached.expires > Date.now()) {
      return cached.data
    }
    
    if (cached) {
      this.memoryCache.delete(key)
    }
    
    return null
  }
  
  private setToMemory<T>(key: string, data: T, ttl: number): void {
    this.memoryCache.set(key, {
      data,
      expires: Date.now() + ttl
    })
    
    // 清理过期缓存
    this.cleanupMemoryCache()
  }
  
  private cleanupMemoryCache(): void {
    const now = Date.now()
    for (const [key, value] of this.memoryCache.entries()) {
      if (value.expires <= now) {
        this.memoryCache.delete(key)
      }
    }
  }
  
  private getFullKey(key: string, namespace?: string): string {
    return namespace ? `${namespace}:${key}` : key
  }
}

// 单例模式
export const cacheManager = new CacheManager()

智能缓存策略实现

// composables/useSmartCache.ts
export const useSmartCache = () => {
  const getCacheStrategy = (path: string) => {
    // 基于路径确定缓存策略
    if (path.startsWith('/api/static/')) {
      return { ttl: 86400000, storage: 'localStorage' } // 1天
    }
    
    if (path.startsWith('/api/user/')) {
      return { ttl: 300000, storage: 'sessionStorage' } // 5分钟
    }
    
    if (path.startsWith('/api/realtime/')) {
      return { ttl: 30000, storage: 'memory' } // 30秒
    }
    
    return { ttl: 600000, storage: 'memory' } // 默认10分钟
  }
  
  const cachedFetch = async <T>(
    url: string, 
    options?: RequestInit
  ): Promise<T> => {
    const cacheKey = `fetch:${url}:${JSON.stringify(options)}`
    const strategy = getCacheStrategy(url)
    
    // 尝试从缓存获取
    const cached = await cacheManager.get<T>(cacheKey, strategy)
    if (cached !== null) {
      return cached
    }
    
    // 执行请求
    const result = await $fetch<T>(url, options)
    
    // 存储到缓存
    await cacheManager.set(cacheKey, result, strategy)
    
    return result
  }
  
  return { cachedFetch }
}

第四部分:高级优化技术

Nitro 引擎深度优化

边缘渲染和分布式部署

// nitro.config.ts - 边缘优化配置
export default defineNitroConfig({
  // 边缘函数配置
  experimental: {
    wasm: true,
    legacyExternals: false
  },
  
  // 预设配置用于不同平台
  preset: 'cloudflare-pages', // 或 'vercel-edge', 'netlify-edge'
  
  // 路由规则优化
  routeRules: {
    '/': { 
      prerender: true,
      headers: { 'cache-control': 's-maxage=31536000' }
    },
    '/api/edge/**': { 
      headers: { 'cache-control': 's-maxage=60' }
    },
    '/blog/**': { 
      isr: 86400, // 24小时增量静态再生
      headers: { 'cache-control': 's-maxage=86400' }
    }
  },
  
  // 压缩和优化
  minify: true,
  sourceMap: false,
  
  // 存储配置
  storage: {
    redis: {
      driver: 'redis',
      host: process.env.REDIS_HOST || 'localhost',
      port: process.env.REDIS_PORT || 6379,
      password: process.env.REDIS_PASSWORD
    }
  }
})

服务端组件和岛屿架构

<!-- components/ServerOnlyComponent.vue -->
<template>
  <div class="server-component">
    <h2>{{ data.title }}</h2>
    <p>{{ data.description }}</p>
    
    <!-- 服务端渲染的复杂内容 -->
    <div v-html="data.processedContent"></div>
  </div>
</template>

<script setup>
// 服务端专用组件,不会发送到客户端
defineOptions({
  _hydrationKey: false // 禁用水合
})

const { data } = await $fetch('/api/server-data')

// 服务端处理复杂逻辑
const processContent = (content: string) => {
  // 复杂的内容处理逻辑
  return content.replace(/\[([^\]]+)\]/g, '<strong>$1</strong>')
}

data.processedContent = processContent(data.content)
</script>
<!-- pages/hybrid-example.vue -->
<template>
  <div>
    <!-- 服务端组件 -->
    <NuxtIsland name="ServerOnlyComponent" />
    
    <!-- 客户端交互组件 -->
    <ClientOnly>
      <InteractiveWidget />
    </ClientOnly>
    
    <!-- 混合组件 -->
    <HybridComponent :initial-data="serverData" />
  </div>
</template>

<script setup>
// 服务端数据预取
const { data: serverData } = await useFetch('/api/initial-data')
</script>

模块化性能优化

关键性能模块集成

// nuxt.config.ts - 性能模块配置
export default defineNuxtConfig({
  modules: [
    '@nuxt/image',
    '@nuxtjs/fontaine',
    'nuxt-delay-hydration',
    '@nuxtjs/partytown',
    '@nuxt/scripts'
  ],
  
  // 图像优化模块
  image: {
    provider: 'cloudinary',
    cloudinary: {
      baseURL: 'https://res.cloudinary.com/your-cloud/image/fetch/'
    },
    presets: {
      cover: {
        modifiers: {
          fit: 'cover',
          format: 'avif,webp,jpg',
          quality: 'auto:best'
        }
      }
    }
  },
  
  // 字体优化模块
  fontMetrics: {
    fonts: ['Inter', 'JetBrains Mono']
  },
  
  // 延迟水合模块
  delayHydration: {
    mode: 'mount',
    debug: process.env.NODE_ENV === 'development'
  },
  
  // Partytown 配置(第三方脚本优化)
  partytown: {
    forward: ['dataLayer.push']
  },
  
  // 脚本优化模块
  scripts: {
    registry: {
      googleAnalytics: {
        id: 'G-XXXXXXXXXX'
      }
    }
  }
})

自定义性能优化插件

// plugins/performance-monitor.client.ts
export default defineNuxtPlugin(() => {
  if (process.client) {
    // 性能监控
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        // 发送性能数据到分析服务
        if (entry.name === 'largest-contentful-paint') {
          sendMetric('lcp', entry.startTime)
        }
        
        if (entry.name === 'first-input-delay') {
          sendMetric('fid', entry.processingStart - entry.startTime)
        }
        
        if (entry.name === 'cumulative-layout-shift') {
          sendMetric('cls', entry.value)
        }
      }
    })
    
    observer.observe({ type: 'largest-contentful-paint', buffered: true })
    observer.observe({ type: 'first-input', buffered: true })
    observer.observe({ type: 'layout-shift', buffered: true })
    
    // 自定义性能指标
    const measureNavigationTiming = () => {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
      
      const metrics = {
        dns: navigation.domainLookupEnd - navigation.domainLookupStart,
        tcp: navigation.connectEnd - navigation.connectStart,
        ttfb: navigation.responseStart - navigation.requestStart,
        download: navigation.responseEnd - navigation.responseStart,
        domLoad: navigation.domContentLoadedEventEnd - navigation.navigationStart,
        windowLoad: navigation.loadEventEnd - navigation.navigationStart
      }
      
      sendMetrics(metrics)
    }
    
    // 页面加载完成后测量
    window.addEventListener('load', measureNavigationTiming)
  }
})

const sendMetric = (name: string, value: number) => {
  if (navigator.sendBeacon) {
    const data = JSON.stringify({ metric: name, value, timestamp: Date.now() })
    navigator.sendBeacon('/api/metrics', data)
  }
}

const sendMetrics = (metrics: Record<string, number>) => {
  if (navigator.sendBeacon) {
    const data = JSON.stringify({ metrics, timestamp: Date.now() })
    navigator.sendBeacon('/api/metrics', data)
  }
}

监控和诊断体系

性能监控仪表板

// server/api/metrics.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  
  // 存储性能指标
  await useStorage('redis').setItem(
    `metrics:${Date.now()}`,
    {
      ...body,
      userAgent: getHeader(event, 'user-agent'),
      ip: getClientIP(event),
      timestamp: Date.now()
    }
  )
  
  return { status: 'ok' }
})
<!-- components/PerformanceDashboard.vue -->
<template>
  <div class="performance-dashboard">
    <div class="metrics-grid">
      <MetricCard 
        title="Largest Contentful Paint"
        :value="metrics.lcp"
        unit="ms"
        :threshold="2500"
      />
      
      <MetricCard 
        title="First Input Delay"
        :value="metrics.fid"
        unit="ms"
        :threshold="100"
      />
      
      <MetricCard 
        title="Cumulative Layout Shift"
        :value="metrics.cls"
        unit=""
        :threshold="0.1"
      />
      
      <MetricCard 
        title="Time to First Byte"
        :value="metrics.ttfb"
        unit="ms"
        :threshold="800"
      />
    </div>
    
    <PerformanceChart :data="chartData" />
  </div>
</template>

<script setup>
const { data: metrics } = await useFetch('/api/performance/summary')
const { data: chartData } = await useFetch('/api/performance/chart')
</script>

实时性能诊断工具

// composables/usePerformanceDiagnostics.ts
export const usePerformanceDiagnostics = () => {
  const diagnostics = ref({
    bundleSize: 0,
    unusedCSS: [],
    largeImages: [],
    slowQueries: [],
    memoryUsage: 0
  })
  
  const runDiagnostics = async () => {
    if (process.client) {
      // 检查包大小
      diagnostics.value.bundleSize = await getBundleSize()
      
      // 检查未使用的 CSS
      diagnostics.value.unusedCSS = await getUnusedCSS()
      
      // 检查大图像
      diagnostics.value.largeImages = await getLargeImages()
      
      // 检查内存使用
      diagnostics.value.memoryUsage = getMemoryUsage()
    }
    
    if (process.server) {
      // 检查慢查询
      diagnostics.value.slowQueries = await getSlowQueries()
    }
  }
  
  const getBundleSize = async (): Promise<number> => {
    const entries = performance.getEntriesByType('resource')
    return entries
      .filter(entry => entry.name.includes('.js'))
      .reduce((total, entry) => total + (entry as any).transferSize, 0)
  }
  
  const getUnusedCSS = async (): Promise<string[]> => {
    const stylesheets = Array.from(document.styleSheets)
    const unusedRules: string[] = []
    
    for (const stylesheet of stylesheets) {
      try {
        const rules = Array.from(stylesheet.cssRules)
        for (const rule of rules) {
          if (rule instanceof CSSStyleRule) {
            if (!document.querySelector(rule.selectorText)) {
              unusedRules.push(rule.selectorText)
            }
          }
        }
      } catch (e) {
        // Cross-origin stylesheets
      }
    }
    
    return unusedRules
  }
  
  const getLargeImages = async (): Promise<Array<{src: string, size: number}>> => {
    const images = Array.from(document.images)
    const largeImages: Array<{src: string, size: number}> = []
    
    for (const img of images) {
      const entry = performance.getEntriesByName(img.src)[0] as any
      if (entry && entry.transferSize > 100000) { // 100KB
        largeImages.push({
          src: img.src,
          size: entry.transferSize
        })
      }
    }
    
    return largeImages
  }
  
  const getMemoryUsage = (): number => {
    return (performance as any).memory?.usedJSHeapSize || 0
  }
  
  const getSlowQueries = async (): Promise<string[]> => {
    // 服务端查询性能监控
    return await $fetch('/api/performance/slow-queries')
  }
  
  return {
    diagnostics: readonly(diagnostics),
    runDiagnostics
  }
}

第五部分:企业级性能优化实践

大规模应用性能优化

微前端架构下的性能优化

// nuxt.config.ts - 微前端配置
export default defineNuxtConfig({
  // 模块联邦配置
  vite: {
    build: {
      rollupOptions: {
        external: ['vue', '@vue/shared'],
        output: {
          globals: {
            vue: 'Vue'
          }
        }
      }
    },
    plugins: [
      // 模块联邦插件
      federation({
        name: 'host-app',
        remotes: {
          'micro-app-1': 'http://localhost:3001/assets/remoteEntry.js',
          'micro-app-2': 'http://localhost:3002/assets/remoteEntry.js'
        },
        shared: {
          vue: {
            singleton: true,
            requiredVersion: '^3.0.0'
          }
        }
      })
    ]
  },
  
  // 路由配置
  hooks: {
    'render:route': (url, result, context) => {
      // 动态路由分发到微应用
      if (url.startsWith('/micro-app-1')) {
        return loadMicroApp('micro-app-1', url, context)
      }
    }
  }
})

多环境性能优化策略

// config/performance.config.ts
interface PerformanceConfig {
  cacheStrategy: 'aggressive' | 'moderate' | 'minimal'
  bundleSplitting: boolean
  imageOptimization: boolean
  serverRendering: boolean
}

const getPerformanceConfig = (): PerformanceConfig => {
  const env = process.env.NODE_ENV
  const isProduction = env === 'production'
  
  return {
    cacheStrategy: isProduction ? 'aggressive' : 'minimal',
    bundleSplitting: isProduction,
    imageOptimization: isProduction,
    serverRendering: isProduction
  }
}

export const performanceConfig = getPerformanceConfig()

持续性能优化流程

CI/CD 性能检查

# .github/workflows/performance.yml
name: Performance Check

on:
  pull_request:
    branches: [main]

jobs:
  performance-audit:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build application
        run: npm run build
      
      - name: Run Lighthouse CI
        run: |
          npm install -g @lhci/cli
          lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
      
      - name: Bundle size check
        run: |
          npm run build:analyze
          node scripts/bundle-size-check.js
      
      - name: Performance regression test
        run: npm run test:performance
// scripts/bundle-size-check.js
const fs = require('fs')
const path = require('path')

const MAX_BUNDLE_SIZE = 250 * 1024 // 250KB
const BUILD_DIR = '.output/public/_nuxt'

const checkBundleSize = () => {
  const files = fs.readdirSync(BUILD_DIR)
  const jsFiles = files.filter(file => file.endsWith('.js'))
  
  let totalSize = 0
  const largeBundles = []
  
  jsFiles.forEach(file => {
    const filePath = path.join(BUILD_DIR, file)
    const stats = fs.statSync(filePath)
    const size = stats.size
    
    totalSize += size
    
    if (size > MAX_BUNDLE_SIZE) {
      largeBundles.push({ file, size })
    }
  })
  
  console.log(`Total JS bundle size: ${(totalSize / 1024).toFixed(2)}KB`)
  
  if (largeBundles.length > 0) {
    console.error('Large bundles detected:')
    largeBundles.forEach(({ file, size }) => {
      console.error(`- ${file}: ${(size / 1024).toFixed(2)}KB`)
    })
    process.exit(1)
  }
  
  console.log('✅ Bundle size check passed')
}

checkBundleSize()

最佳实践总结

性能优化检查清单

构建时优化

  • 启用代码分割和 Tree Shaking
  • 配置图像和字体优化
  • 实施 CSS 优化和关键路径分离
  • 设置依赖分析和包大小监控
  • 配置压缩和最小化

运行时优化

  • 实施智能缓存策略
  • 优化数据获取和状态管理
  • 配置服务端渲染优化
  • 实施懒加载和延迟水合
  • 设置性能监控和诊断

部署和监控

  • 配置 CDN 和边缘计算
  • 设置性能监控仪表板
  • 实施 CI/CD 性能检查
  • 配置错误监控和告警
  • 建立性能优化迭代流程

性能优化注意事项

推荐的性能优化工具

  • 分析工具: Lighthouse, WebPageTest, Chrome DevTools
  • 监控工具: Google Analytics, Sentry, LogRocket
  • 构建工具: Vite, Webpack Bundle Analyzer
  • 图像优化: Cloudinary, ImageKit, TinyPNG
  • CDN服务: Cloudflare, AWS CloudFront, Vercel

通过系统性地应用本指南中的优化策略,您可以构建出高性能、可扩展的 Nuxt 应用,为用户提供卓越的 Web 体验。记住,性能优化是一个持续的过程,需要根据应用的发展和用户反馈不断调整和改进。