Element Plus SSR 服务端渲染支持与配置
学习目标
- 理解 SSR 在 Element Plus 中的应用场景
- 掌握 Element Plus SSR 配置方法
- 解决 SSR 中的常见问题
- 学习水合错误的避免方法
学习内容
1. SSR 基础概念
1.1 什么是 SSR
- 服务端渲染:在服务器端生成完整的 HTML
- 客户端激活:在浏览器端激活交互功能
- 同构应用:同一套代码在服务端和客户端运行
1.2 SSR 的优势
- SEO 友好:搜索引擎可以直接抓取内容
- 首屏加载快:减少白屏时间
- 更好的用户体验:快速显示内容
2. Element Plus SSR 配置
2.1 基础配置
typescript
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@element-plus/nuxt'],
elementPlus: {
/** Options */
}
})
2.2 手动配置
typescript
// plugins/element-plus.client.ts
import { ID_INJECTION_KEY } from '@element-plus/tokens'
import { ElMessage } from 'element-plus'
export default defineNuxtPlugin({
name: 'element-plus',
parallel: true,
setup(nuxtApp) {
if (process.client) {
nuxtApp.vueApp.provide(ID_INJECTION_KEY, {
prefix: Math.floor(Math.random() * 10000),
current: 0,
})
}
},
})
3. 解决 SSR 常见问题
3.1 ID 不一致问题
typescript
// 服务端和客户端 ID 同步
import { ID_INJECTION_KEY } from '@element-plus/tokens'
// 在应用入口提供 ID 注入
app.provide(ID_INJECTION_KEY, {
prefix: 1024,
current: 0,
})
3.2 ZIndex 管理
typescript
// 统一 ZIndex 管理
import { ZINDEX_INJECTION_KEY } from '@element-plus/tokens'
app.provide(ZINDEX_INJECTION_KEY, {
current: 2000
})
3.3 Teleport 处理
vue
<!-- 确保 Teleport 目标存在 -->
<template>
<div>
<!-- 页面内容 -->
<div id="teleport-target"></div>
<!-- 使用 Teleport 的组件 -->
<el-dialog v-model="visible" teleported>
<p>Dialog content</p>
</el-dialog>
</div>
</template>
<script setup>
// 确保在客户端渲染时 Teleport 目标已存在
onMounted(() => {
if (!document.getElementById('teleport-target')) {
const target = document.createElement('div')
target.id = 'teleport-target'
document.body.appendChild(target)
}
})
</script>
4. 水合错误避免
4.1 条件渲染处理
vue
<template>
<div>
<!-- 避免服务端和客户端渲染不一致 -->
<ClientOnly>
<el-date-picker v-model="date" />
<template #fallback>
<div>Loading...</div>
</template>
</ClientOnly>
</div>
</template>
4.2 动态内容处理
vue
<template>
<div>
<!-- 使用 key 强制重新渲染 -->
<el-table :data="tableData" :key="tableKey">
<el-table-column prop="name" label="Name" />
</el-table>
</div>
</template>
<script setup>
const tableKey = ref(0)
const tableData = ref([])
onMounted(() => {
// 客户端数据加载完成后更新 key
loadTableData().then(() => {
tableKey.value++
})
})
</script>
5. Nuxt 3 集成
5.1 安装和配置
bash
# 安装 Element Plus Nuxt 模块
npm install @element-plus/nuxt -D
typescript
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@element-plus/nuxt'
],
elementPlus: {
/** 配置选项 */
importStyle: 'scss',
themes: ['dark']
}
})
5.2 组件使用
vue
<!-- pages/index.vue -->
<template>
<div>
<el-button @click="handleClick">Click me</el-button>
<el-message-box v-model="visible" title="Title">
Content
</el-message-box>
</div>
</template>
<script setup>
const visible = ref(false)
const handleClick = () => {
ElMessage.success('Hello from SSR!')
}
</script>
6. Next.js 集成
6.1 配置 Next.js
javascript
// next.config.js
const withTM = require('next-transpile-modules')([
'element-plus'
])
module.exports = withTM({
// 其他配置
})
6.2 动态导入
typescript
// components/ElementPlusComponents.tsx
import dynamic from 'next/dynamic'
const ElButton = dynamic(
() => import('element-plus').then(mod => mod.ElButton),
{ ssr: false }
)
export { ElButton }
7. 性能优化
7.1 按需加载
typescript
// 只在需要时加载组件
const LazyDialog = defineAsyncComponent(() =>
import('element-plus').then(mod => mod.ElDialog)
)
7.2 预加载关键组件
typescript
// 预加载常用组件
const preloadComponents = () => {
import('element-plus/es/components/button')
import('element-plus/es/components/input')
import('element-plus/es/components/form')
}
if (process.client) {
preloadComponents()
}
8. 实践练习
练习1:Nuxt 3 项目搭建
bash
# 创建 Nuxt 3 项目
npx nuxi@latest init element-plus-ssr
cd element-plus-ssr
# 安装 Element Plus
npm install @element-plus/nuxt -D
# 配置和运行
npm run dev
练习2:解决水合错误
vue
<!-- 创建一个避免水合错误的组件 -->
<template>
<div>
<ClientOnly>
<el-date-picker
v-model="selectedDate"
type="datetime"
placeholder="Select date and time"
/>
</ClientOnly>
</div>
</template>
<script setup>
const selectedDate = ref(new Date())
</script>
练习3:SSR 性能测试
typescript
// 测试 SSR 性能
const measureSSRPerformance = () => {
const start = performance.now()
// 渲染组件
const app = createSSRApp(App)
const html = renderToString(app)
const end = performance.now()
console.log(`SSR rendering took ${end - start} milliseconds`)
return html
}
学习资源
作业
- 搭建一个 Element Plus + Nuxt 3 的 SSR 项目
- 解决项目中的水合错误问题
- 优化 SSR 性能和首屏加载时间
下一步
明天我们将学习 Element Plus 的 Teleport 机制与弹出层处理。