渲染模式✅
本主题涵盖 Nuxt 的多种渲染模式,包括 SSR、SSG、SPA 和混合渲染的特点、使用场景和配置方式。
Nuxt 支持哪些渲染模式,各有什么特点?
答案
核心概念
Nuxt 支持多种渲染模式,每种模式都有其特定的使用场景和优势,开发者可以根据项目需求选择合适的渲染策略。
主要渲染模式
渲染模式 | 全称 | 特点 | 适用场景 |
---|---|---|---|
SSR | Server-Side Rendering | 服务端渲染,每次请求生成 HTML | 动态内容、SEO 重要 |
SSG | Static Site Generation | 静态站点生成,构建时预渲染 | 静态内容、高性能 |
SPA | Single Page Application | 单页应用,客户端渲染 | 交互性强、用户个性化 |
混合渲染 | Hybrid Rendering | 不同页面使用不同渲染模式 | 复杂应用、灵活需求 |
详细对比
-
SSR (服务端渲染)
// nuxt.config.ts
export default defineNuxtConfig({
ssr: true // 默认值
})- 优势:SEO 友好、首屏加载快、动态内容支持
- 劣势:服务器负载高、缓存复杂
- 适用:电商网站、新闻网站、博客
-
SSG (静态站点生成)
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
prerender: {
routes: ['/'] // 预渲染路由
}
}
})- 优势:性能最佳、CDN 友好、服务器成本低
- 劣势:动态内容支持有限、构建时间长
- 适用:文档网站、营销页面、博客
-
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 应用中,不同的页面使用不同的渲染模式,实现最优的性能和用户体验。
实现方式
-
页面级渲染模式
<!-- 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> -
路由级渲染模式
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
prerender: {
routes: [
'/', // 首页 SSG
'/about', // 关于页面 SSG
'/contact' // 联系页面 SSG
]
}
}
}) -
动态渲染模式
<!-- 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 }
}
})
性能优化策略
-
静态内容 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> -
动态内容 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> -
交互应用 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 应用性能优化需要从多个维度考虑,包括渲染模式选择、缓存策略、代码分割、资源优化等方面。
主要优化策略
-
渲染模式优化
- 静态内容使用 SSG
- 动态内容使用 SSR
- 交互应用使用 SPA
-
缓存策略
- 页面级缓存
- API 缓存
- 静态资源缓存
-
代码分割
- 路由级分割
- 组件级分割
- 第三方库分割
详细优化方案
-
页面级缓存
// 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' }
}
}
}) -
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
}) -
组件懒加载
<!-- 懒加载组件 -->
<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> -
图片优化
<template>
<div>
<!-- 使用 NuxtImg 组件优化图片 -->
<NuxtImg
src="/images/product.jpg"
alt="产品图片"
width="300"
height="200"
loading="lazy"
placeholder
/>
</div>
</template> -
代码分割配置
// 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>
面试官视角
该题考察候选人对性能优化的理解,是构建高质量应用的重要技能。通过此题可以引出缓存策略、代码分割、资源优化等更深层的优化技巧。
延伸阅读