Nuxt.js性能优化 #

一、性能指标 #

1.1 核心指标 #

指标 说明 目标值
LCP 最大内容绘制 < 2.5s
FID 首次输入延迟 < 100ms
CLS 累积布局偏移 < 0.1
TTFB 首字节时间 < 600ms
TTI 可交互时间 < 3.8s

1.2 性能分析工具 #

  • Chrome DevTools
  • Lighthouse
  • WebPageTest
  • Nuxt DevTools

二、代码分割 #

2.1 路由级分割 #

Nuxt 自动按页面分割代码。

2.2 组件懒加载 #

vue
<template>
  <LazyHeavyComponent v-if="show" />
</template>

2.3 动态导入 #

vue
<script setup lang="ts">
const HeavyLibrary = defineAsyncComponent(() =>
  import('~/components/HeavyLibrary.vue')
)
</script>

2.4 手动分包 #

nuxt.config.ts

typescript
export default defineNuxtConfig({
  vite: {
    build: {
      rollupOptions: {
        output: {
          manualChunks: {
            'vendor': ['vue', 'vue-router', 'pinia'],
            'ui': ['@vueuse/core']
          }
        }
      }
    }
  }
})

三、图片优化 #

3.1 使用Nuxt Image #

bash
pnpm add @nuxt/image

nuxt.config.ts

typescript
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  
  image: {
    quality: 80,
    format: ['webp', 'avif'],
    screens: {
      xs: 320,
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1280
    }
  }
})

3.2 使用优化图片 #

vue
<template>
  <NuxtImg
    src="/image.jpg"
    width="600"
    height="400"
    format="webp"
    loading="lazy"
    placeholder
  />
</template>

3.3 响应式图片 #

vue
<template>
  <NuxtPicture
    src="/hero.jpg"
    width="1200"
    height="600"
    :img-attrs="{ class: 'hero-image' }"
  />
</template>

3.4 图片预加载 #

vue
<script setup lang="ts">
useHead({
  link: [
    { rel: 'preload', as: 'image', href: '/hero.webp' }
  ]
})
</script>

四、字体优化 #

4.1 字体预加载 #

typescript
export default defineNuxtConfig({
  app: {
    head: {
      link: [
        { rel: 'preconnect', href: 'https://fonts.googleapis.com' },
        { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: true },
        { rel: 'preload', as: 'style', href: 'https://fonts.googleapis.com/css2?family=Inter&display=swap' }
      ]
    }
  }
})

4.2 本地字体 #

css
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

4.3 字体显示策略 #

css
font-display: swap;

五、缓存策略 #

5.1 路由缓存 #

typescript
export default defineNuxtConfig({
  routeRules: {
    '/': { isr: 3600 },
    '/blog/**': { isr: 86400 },
    '/api/**': { cache: { maxAge: 60 } }
  }
})

5.2 静态资源缓存 #

typescript
export default defineNuxtConfig({
  nitro: {
    compressPublicAssets: true
  }
})

5.3 API缓存 #

typescript
export default defineCachedEventHandler(
  async () => {
    return await fetchData()
  },
  {
    maxAge: 60 * 60,
    swr: true
  }
)

六、预加载与预取 #

6.1 链接预取 #

vue
<template>
  <NuxtLink to="/about" prefetch>关于</NuxtLink>
</template>

6.2 全局预取配置 #

typescript
export default defineNuxtConfig({
  router: {
    options: {
      prefetchLinks: true
    }
  }
})

6.3 手动预取 #

vue
<script setup lang="ts">
const { prefetch } = useRouter()

onMounted(() => {
  prefetch('/important-page')
})
</script>

6.4 预加载关键资源 #

vue
<script setup lang="ts">
useHead({
  link: [
    { rel: 'preload', as: 'script', href: '/critical.js' },
    { rel: 'preload', as: 'style', href: '/critical.css' }
  ]
})
</script>

七、服务端优化 #

7.1 流式渲染 #

vue
<script setup lang="ts">
const { data } = await useFetch('/api/data', {
  lazy: true
})
</script>

7.2 并行数据获取 #

vue
<script setup lang="ts">
const [users, posts] = await Promise.all([
  useFetch('/api/users'),
  useFetch('/api/posts')
])
</script>

7.3 服务端缓存 #

typescript
export default defineNuxtConfig({
  nitro: {
    storage: {
      cache: {
        driver: 'redis',
        url: process.env.REDIS_URL
      }
    }
  }
})

八、客户端优化 #

8.1 防抖与节流 #

vue
<script setup lang="ts">
import { useDebounceFn, useThrottleFn } from '@vueuse/core'

const debouncedSearch = useDebounceFn(search, 300)
const throttledScroll = useThrottleFn(handleScroll, 100)
</script>

8.2 虚拟列表 #

bash
pnpm add @vueuse/core
vue
<script setup lang="ts">
import { useVirtualList } from '@vueuse/core'

const { list, containerProps, wrapperProps } = useVirtualList(
  largeList,
  { itemHeight: 50 }
)
</script>

<template>
  <div v-bind="containerProps" style="height: 400px; overflow: auto;">
    <div v-bind="wrapperProps">
      <div v-for="{ data, index } in list" :key="index" style="height: 50px;">
        {{ data.name }}
      </div>
    </div>
  </div>
</template>

8.3 骨架屏 #

vue
<template>
  <div v-if="pending" class="skeleton">
    <div class="skeleton-title" />
    <div class="skeleton-text" />
    <div class="skeleton-text" />
  </div>
  <div v-else>
    <h1>{{ data.title }}</h1>
    <p>{{ data.content }}</p>
  </div>
</template>

<style scoped>
.skeleton-title {
  height: 24px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeleton 1.5s infinite;
}

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

@keyframes skeleton {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
</style>

九、打包优化 #

9.1 分析打包体积 #

bash
npx nuxi analyze

9.2 移除未使用的代码 #

typescript
export default defineNuxtConfig({
  vite: {
    build: {
      minify: 'terser',
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      }
    }
  }
})

9.3 压缩配置 #

typescript
export default defineNuxtConfig({
  nitro: {
    compressPublicAssets: true
  }
})

十、监控与分析 #

10.1 性能监控 #

vue
<script setup lang="ts">
onMounted(() => {
  if ('PerformanceObserver' in window) {
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        console.log(entry.name, entry.duration)
      }
    })
    
    observer.observe({ entryTypes: ['measure', 'navigation'] })
  }
})
</script>

10.2 错误追踪 #

typescript
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('app:error', (error) => {
    console.error('Application error:', error)
  })
})

10.3 Web Vitals #

typescript
export default defineNuxtPlugin(() => {
  if (import.meta.client) {
    const reportWebVitals = (metric: any) => {
      console.log(metric)
    }
    
    import('web-vitals').then(({ getCLS, getFID, getLCP }) => {
      getCLS(reportWebVitals)
      getFID(reportWebVitals)
      getLCP(reportWebVitals)
    })
  }
})

十一、最佳实践总结 #

11.1 首屏优化 #

  • 使用 SSR 或 SSG
  • 预加载关键资源
  • 优化字体加载
  • 使用骨架屏

11.2 运行时优化 #

  • 懒加载非关键组件
  • 使用虚拟列表
  • 合理使用缓存
  • 防抖和节流

11.3 打包优化 #

  • 代码分割
  • Tree shaking
  • 压缩资源
  • 分析打包体积

十二、总结 #

本章介绍了 Nuxt.js 性能优化:

  • 核心性能指标
  • 代码分割策略
  • 图片和字体优化
  • 缓存策略配置
  • 预加载与预取
  • 服务端和客户端优化
  • 打包优化
  • 性能监控

性能优化是一个持续的过程,需要不断测量和改进。

最后更新:2026-03-28