[Lv3] SSR 实作难题与解决方案
在 SSR 实作过程中,常见的难题与解决方案:Hydration Mismatch、环境变数处理、第三方套件兼容性、效能优化等。
📋 面试情境题
Q: 在实作 SSR 时,有遇到哪些难题?如何解决?
这是面试中经常会被问到的问题,面试官想了解:
- 实际经验:是否真的实作过 SSR
- 问题解决能力:遇到问题时的思考过程
- 技术深度:对 SSR 原理的理解程度
- 最佳实践:是否有采用业界标准做法
难题 1:Hydration Mismatch 错误
问题描述
错误讯息:
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content.
发生原因:
- Server Side 渲染的 HTML 与 Client Side 渲染的 HTML 不一致
- 常见于使用浏览器专用 API(
window、document、localStorage等) - 时间相关的内容(如:
new Date())在 Server 和 Client 执行时间不同
解决方案
方案 1: 使用 ClientOnly 组件
适用场景: 组件只在客户端渲染
<template>
<div>
<h1>主要内容(SSR)</h1>
<ClientOnly>
<BrowserOnlyComponent />
<template #fallback>
<div>载入中...</div>
</template>
</ClientOnly>
</div>
</template>
优点:
- ✅ 简单直接
- ✅ Nuxt 内建支援
缺点:
- ⚠️ 该部分内容不会在 SSR 中渲染
- ⚠️ 可能影响 SEO
方案 2: 使用 process.client 检查
适用场景: 条件式渲染客户端专用内容
<script setup lang="ts">
const userAgent = ref('');
onMounted(() => {
// 只在客户端执行
if (process.client) {
userAgent.value = navigator.userAgent;
}
});
</script>
<template>
<div>
<p v-if="userAgent">User Agent: {{ userAgent }}</p>
</div>
</template>
关键点:
- ✅ 使用
process.client检查执行环境 - ✅ 避免在 Server Side 存取浏览器 API
方案 3: 使用 onMounted Hook
适用场景: 需要在客户端执行的初始化逻辑
<script setup lang="ts">
const isClient = ref(false);
onMounted(() => {
isClient.value = true;
// 客户端专用的初始化逻辑
initializeClientOnlyFeature();
});
</script>
<template>
<div>
<div v-if="isClient">客户端内容</div>
<div v-else>伺服器端内容(或载入中)</div>
</div>
</template>
方案 4: 统一 Server 和 Client 的资料来源
适用场景: 时间、随机数等会导致不一致的内容
<script setup lang="ts">
// ❌ 错误:Server 和 Client 时间不同
const currentTime = new Date().toISOString();
// ✅ 正确:从 API 取得统一时间
const { data: serverTime } = await useFetch('/api/time');
const currentTime = serverTime.value;
</script>
面试回答范例
在实作 SSR 时,最常遇到的是 Hydration Mismatch 错误。这通常发生在使用浏览器专用 API 时,例如
window、localStorage等。我的解决方式是:首先,使用ClientOnly组件包裹只在客户端渲染的内容;其次,使用process.client检查执行环境,避免在 Server Side 存取浏览器 API;最后,对于时间、随机数等会导致不一致的内容,统一从 Server Side API 取得,确保 Server 和 Client 的资料一致。