跳到主要内容

渲染模式✅

本主题涵盖 Nuxt 的多种渲染模式,包括 SSR、SSG、SPA 和混合渲染的特点、使用场景和配置方式。

Nuxt 支持哪些渲染模式,各有什么特点?

答案

核心概念

Nuxt 支持多种渲染模式,每种模式都有其特定的使用场景和优势,开发者可以根据项目需求选择合适的渲染策略。

主要渲染模式

渲染模式全称特点适用场景
SSRServer-Side Rendering服务端渲染,每次请求生成 HTML动态内容、SEO 重要
SSGStatic Site Generation静态站点生成,构建时预渲染静态内容、高性能
SPASingle Page Application单页应用,客户端渲染交互性强、用户个性化
混合渲染Hybrid Rendering不同页面使用不同渲染模式复杂应用、灵活需求

详细对比

  1. SSR (服务端渲染)

    // nuxt.config.ts
    export default defineNuxtConfig({
    ssr: true // 默认值
    })
    • 优势:SEO 友好、首屏加载快、动态内容支持
    • 劣势:服务器负载高、缓存复杂
    • 适用:电商网站、新闻网站、博客
  2. SSG (静态站点生成)

    // nuxt.config.ts
    export default defineNuxtConfig({
    nitro: {
    prerender: {
    routes: ['/'] // 预渲染路由
    }
    }
    })
    • 优势:性能最佳、CDN 友好、服务器成本低
    • 劣势:动态内容支持有限、构建时间长
    • 适用:文档网站、营销页面、博客
  3. SPA (单页应用)

    // nuxt.config.ts
    export default defineNuxtConfig({
    ssr: false
    })
    • 优势:用户体验好、服务器负载低、开发简单
    • 劣势:SEO 不友好、首屏加载慢
    • 适用:管理后台、用户仪表盘、游戏应用

示例说明

<!-- pages/index.vue - SSR 页面 -->
<template>
<div>
<h1>首页</h1>
<p>当前时间: {{ currentTime }}</p>
<ArticleList :articles="articles" />
</div>
</template>

<script setup>
// 服务端渲染时执行
const currentTime = new Date().toLocaleString()
const { data: articles } = await $fetch('/api/articles')
</script>
<!-- pages/blog/[slug].vue - SSG 页面 -->
<template>
<div>
<h1>{{ article.title }}</h1>
<div v-html="article.content"></div>
</div>
</template>

<script setup>
// 构建时预渲染
const route = useRoute()
const { data: article } = await $fetch(`/api/articles/${route.params.slug}`)
</script>

面试官视角

该题考察候选人对不同渲染模式的理解,是 Nuxt 开发的核心概念。通过此题可以引出性能优化、SEO 策略等更深层的技术点。

延伸阅读

什么是混合渲染,如何实现?

答案

核心概念

混合渲染允许在同一个 Nuxt 应用中,不同的页面使用不同的渲染模式,实现最优的性能和用户体验。

实现方式

  1. 页面级渲染模式

    <!-- pages/index.vue - SSR -->
    <template>
    <div>首页内容</div>
    </template>

    <script setup>
    // 默认 SSR
    </script>
    <!-- pages/admin.vue - SPA -->
    <template>
    <div>管理后台</div>
    </template>

    <script setup>
    // 指定为 SPA 模式
    definePageMeta({
    ssr: false
    })
    </script>
  2. 路由级渲染模式

    // nuxt.config.ts
    export default defineNuxtConfig({
    nitro: {
    prerender: {
    routes: [
    '/', // 首页 SSG
    '/about', // 关于页面 SSG
    '/contact' // 联系页面 SSG
    ]
    }
    }
    })
  3. 动态渲染模式

    <!-- pages/products/[id].vue -->
    <template>
    <div>
    <h1>{{ product.name }}</h1>
    <p>{{ product.description }}</p>
    </div>
    </template>

    <script setup>
    const route = useRoute()
    const productId = route.params.id

    // 根据产品类型决定渲染模式
    const { data: product } = await $fetch(`/api/products/${productId}`)

    // 热门产品使用 SSR,其他使用 SSG
    if (product.isPopular) {
    // SSR 模式
    } else {
    // SSG 模式
    }
    </script>

实际应用场景

// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
prerender: {
routes: [
// 静态页面 - SSG
'/',
'/about',
'/contact',
'/privacy',
'/terms'

// 动态页面 - SSR
// 产品详情页、用户个人页面等
]
}
},

// 特定路由的渲染配置
routeRules: {
// 首页使用 SSG
'/': { prerender: true },

// 关于页面使用 SSG
'/about': { prerender: true },

// 产品页面使用 SSR
'/products/**': { ssr: true },

// 管理后台使用 SPA
'/admin/**': { ssr: false },

// API 路由
'/api/**': { cors: true }
}
})

性能优化策略

  1. 静态内容 SSG

    <!-- pages/blog/[slug].vue -->
    <template>
    <div>
    <h1>{{ post.title }}</h1>
    <div v-html="post.content"></div>
    </div>
    </template>

    <script setup>
    // 博客文章通常是静态内容,适合 SSG
    const route = useRoute()
    const { data: post } = await $fetch(`/api/posts/${route.params.slug}`)
    </script>
  2. 动态内容 SSR

    <!-- pages/user/[id].vue -->
    <template>
    <div>
    <h1>{{ user.name }}</h1>
    <p>最后登录: {{ user.lastLogin }}</p>
    </div>
    </template>

    <script setup>
    // 用户信息是动态的,适合 SSR
    const route = useRoute()
    const { data: user } = await $fetch(`/api/users/${route.params.id}`)
    </script>
  3. 交互应用 SPA

    <!-- pages/dashboard.vue -->
    <template>
    <div>
    <h1>用户仪表盘</h1>
    <ChartComponent :data="chartData" />
    <RealTimeUpdates />
    </div>
    </template>

    <script setup>
    // 仪表盘需要实时交互,适合 SPA
    definePageMeta({
    ssr: false
    })
    </script>

配置最佳实践

// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 首页和静态页面
'/': { prerender: true },
'/about': { prerender: true },
'/contact': { prerender: true },

// 动态内容页面
'/products/**': { ssr: true },
'/users/**': { ssr: true },

// 管理后台
'/admin/**': { ssr: false },

// API 路由
'/api/**': {
cors: true,
headers: { 'cache-control': 's-maxage=60' }
}
}
})

面试官视角

该题考察候选人对混合渲染的理解,是构建高性能应用的重要技术。通过此题可以引出性能优化、缓存策略等更深层的优化技巧。

延伸阅读

如何优化 Nuxt 应用的渲染性能?

答案

核心概念

Nuxt 应用性能优化需要从多个维度考虑,包括渲染模式选择、缓存策略、代码分割、资源优化等方面。

主要优化策略

  1. 渲染模式优化

    • 静态内容使用 SSG
    • 动态内容使用 SSR
    • 交互应用使用 SPA
  2. 缓存策略

    • 页面级缓存
    • API 缓存
    • 静态资源缓存
  3. 代码分割

    • 路由级分割
    • 组件级分割
    • 第三方库分割

详细优化方案

  1. 页面级缓存

    // nuxt.config.ts
    export default defineNuxtConfig({
    routeRules: {
    // 静态页面长期缓存
    '/': {
    prerender: true,
    headers: { 'cache-control': 's-maxage=31536000' }
    },

    // 动态页面短期缓存
    '/products/**': {
    ssr: true,
    headers: { 'cache-control': 's-maxage=300' }
    },

    // 实时页面不缓存
    '/live/**': {
    ssr: true,
    headers: { 'cache-control': 'no-cache' }
    }
    }
    })
  2. API 缓存优化

    // server/api/products/[id].get.ts
    export default defineEventHandler(async (event) => {
    const id = getRouterParam(event, 'id')

    // 使用缓存
    const cached = await useStorage('cache').getItem(`product:${id}`)
    if (cached) {
    return cached
    }

    // 获取数据
    const product = await getProduct(id)

    // 缓存数据
    await useStorage('cache').setItem(`product:${id}`, product, {
    ttl: 300 // 5分钟缓存
    })

    return product
    })
  3. 组件懒加载

    <!-- 懒加载组件 -->
    <template>
    <div>
    <h1>产品列表</h1>
    <LazyProductCard
    v-for="product in products"
    :key="product.id"
    :product="product"
    />
    </div>
    </template>

    <script setup>
    // 懒加载组件,只在需要时加载
    const LazyProductCard = defineAsyncComponent(() =>
    import('~/components/ProductCard.vue')
    )
    </script>
  4. 图片优化

    <template>
    <div>
    <!-- 使用 NuxtImg 组件优化图片 -->
    <NuxtImg
    src="/images/product.jpg"
    alt="产品图片"
    width="300"
    height="200"
    loading="lazy"
    placeholder
    />
    </div>
    </template>
  5. 代码分割配置

    // nuxt.config.ts
    export default defineNuxtConfig({
    build: {
    // 代码分割配置
    splitChunks: {
    layouts: true,
    pages: true,
    commons: true
    }
    },

    // 预加载关键资源
    app: {
    head: {
    link: [
    { rel: 'preload', href: '/fonts/main.woff2', as: 'font', type: 'font/woff2', crossorigin: '' }
    ]
    }
    }
    })

性能监控

// plugins/performance.client.ts
export default defineNuxtPlugin(() => {
// 性能监控
if (process.client) {
// 监控页面加载时间
window.addEventListener('load', () => {
const perfData = performance.getEntriesByType('navigation')[0]
console.log('页面加载时间:', perfData.loadEventEnd - perfData.loadEventStart)
})

// 监控 API 请求时间
const originalFetch = window.fetch
window.fetch = async (...args) => {
const start = performance.now()
const response = await originalFetch(...args)
const end = performance.now()
console.log(`API 请求时间: ${end - start}ms`)
return response
}
}
})

实际应用示例

<!-- pages/products/index.vue - 优化的产品列表页 -->
<template>
<div>
<h1>产品列表</h1>

<!-- 使用虚拟滚动优化长列表 -->
<VirtualList
:items="products"
:item-height="200"
:container-height="600"
>
<template #default="{ item }">
<LazyProductCard :product="item" />
</template>
</VirtualList>

<!-- 分页加载 -->
<button
v-if="hasMore"
@click="loadMore"
:disabled="loading"
>
{{ loading ? '加载中...' : '加载更多' }}
</button>
</div>
</template>

<script setup>
// 分页加载数据
const page = ref(1)
const products = ref([])
const hasMore = ref(true)
const loading = ref(false)

const loadMore = async () => {
if (loading.value) return

loading.value = true
try {
const { data: newProducts } = await $fetch(`/api/products?page=${page.value}`)
products.value.push(...newProducts)
page.value++
hasMore.value = newProducts.length > 0
} finally {
loading.value = false
}
}

// 初始加载
await loadMore()
</script>

面试官视角

该题考察候选人对性能优化的理解,是构建高质量应用的重要技能。通过此题可以引出缓存策略、代码分割、资源优化等更深层的优化技巧。

延伸阅读