服务端渲染(SSR)优化
性能优化与服务端渲染(SSR)的关系
服务端渲染(SSR)的核心目标是提升首屏加载性能和SEO友好性,但不当的实现方式反而可能导致性能下降。Vite.js的SSR实现通过独特的架构设计,在开发体验和运行时性能之间取得了平衡。与传统打包工具不同,Vite的SSR构建利用了浏览器原生ES模块系统,避免了不必要的打包开销。
Vite SSR基础架构分析
Vite的SSR实现分为两个独立构建阶段:
- 客户端构建:生成静态资源和客户端入口
- 服务端构建:生成SSR专用的入口模块
典型项目结构示例:
├── src
│ ├── main.js # 通用入口
│ ├── entry-client.js # 客户端入口
│ └── entry-server.js # 服务端入口
├── index.html
└── vite.config.js
关键配置示例:
// vite.config.js
export default defineConfig({
build: {
ssr: true,
rollupOptions: {
input: 'src/entry-server.js'
}
}
})
关键性能优化策略
依赖外部化处理
将node_modules中的依赖标记为external可显著提升SSR构建速度:
// vite.config.js
export default defineConfig({
ssr: {
noExternal: ['需要打包的依赖'],
external: ['应外部化的依赖']
}
})
组件级代码分割
利用动态导入实现组件级懒加载:
// 服务端入口
export default async (url) => {
const { createApp } = await import('./main.js')
const { router } = createApp()
await router.push(url)
await router.isReady()
return renderToString(app)
}
流式渲染优化
通过pipeToNodeStream实现渐进式渲染:
import { renderToNodeStream } from 'vue/server-renderer'
app.use('*', (req, res) => {
const stream = renderToNodeStream(app)
stream.pipe(res, { end: false })
stream.on('end', () => res.end())
})
缓存策略实现
页面级缓存
基于路由的缓存实现示例:
const microCache = new LRU({
max: 100,
maxAge: 1000 * 60 // 1分钟
})
app.get('*', (req, res) => {
const hit = microCache.get(req.url)
if (hit) return res.end(hit)
renderPage(req).then(html => {
microCache.set(req.url, html)
res.end(html)
})
})
组件级缓存
Vue的组件缓存配置:
// server.js
const { createServerRenderer } = require('vite')
const createCache = require('lru-cache')
const componentCache = new createCache({
max: 1000,
maxAge: 1000 * 60 * 15 // 15分钟
})
const renderer = await createServerRenderer({
componentCacheKey: (component) => {
return component.type.__file || component.type.name
},
componentCache
})
内存管理优化
内存泄漏预防
SSR常见的内存泄漏场景处理:
// 确保每个请求有独立的应用实例
const createApp = () => {
const app = express()
app.use('*', async (req, res) => {
const vueApp = createVueApp() // 每个请求新建实例
try {
const html = await renderToString(vueApp)
res.send(html)
} finally {
// 清理工作
vueApp.unmount()
}
})
return app
}
大JSON序列化优化
使用devalue替代JSON.stringify:
import devalue from 'devalue'
const state = { /* 大型状态对象 */ }
const serialized = devalue(state)
const html = `
<script>window.__INITIAL_STATE__ = ${serialized}</script>
`
构建时优化技巧
预编译静态内容
将静态部分提前编译为字符串:
// 构建脚本
import { renderToString } from 'vue/server-renderer'
import staticComponent from './StaticComponent.vue'
const staticHTML = renderToString(staticComponent)
fs.writeFileSync('dist/static.html', staticHTML)
// 服务端使用
const finalHTML = `
${staticHTML}
${dynamicHTML}
`
多进程渲染
利用worker_threads并行渲染:
import { Worker } from 'worker_threads'
function renderInWorker(url) {
return new Promise((resolve) => {
const worker = new Worker('./render-worker.js', {
workerData: { url }
})
worker.on('message', resolve)
})
}
// render-worker.js
const { parentPort, workerData } = require('worker_threads')
renderPage(workerData.url).then(html => {
parentPort.postMessage(html)
})
监控与性能指标
SSR性能指标收集
关键指标监控实现:
app.use((req, res, next) => {
const start = Date.now()
res.on('finish', () => {
const duration = Date.now() - start
metrics.track('ssr_render_time', duration)
})
next()
})
错误边界处理
组件级错误捕获:
// ErrorBoundary.vue
export default {
errorCaptured(err) {
sendErrorToMonitoring(err)
return false // 阻止错误继续向上传播
}
}
生产环境特定优化
基于压力的降级策略
在服务器高负载时降级为CSR:
const shouldDegrade = () => {
return process.memoryUsage().rss > 500 * 1024 * 1024 // 500MB
}
app.use('*', (req, res) => {
if (shouldDegrade()) {
return res.sendFile('dist/client/index.html')
}
// 正常SSR处理
})
智能预加载策略
根据用户行为预测预加载:
// 在布局组件中
onMounted(() => {
const links = [...document.querySelectorAll('a[href]')]
links.forEach(link => {
link.addEventListener('mouseenter', () => {
if (isLikelyNextPage(link)) {
prefetchSSRBundle(link.href)
}
}, { once: true })
})
})
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:长缓存策略与文件哈希