尽管 Vue 的 SSR 速度相当快,但由于创建组件实例和虚拟 DOM 节点的成本,它无法与纯基于字符串的模板的性能相匹配。在 SSR 性能至关重要的情况下,明智地利用缓存策略可以极大地缩短响应时间并减少服务器负载。
缓存能够更快的将内容发送给客户端,提升 web
应用程序的性能,同时减少服务器的负载。
页面缓存
如官方文档中介绍的那样,对特定的页面合理的应用 micro-caching 能够大大改善服务器处理并发的能力(吞吐率 RPS
)。
但并非所有页面都适合应用 micro-caching 缓存策略,我们可以将资源分为三类:
- 静态资源:如
js
、css
、images
等。 - 用户特定的动态资源:不同的用户访问相同的资源会得到不同的内容。
- 用户无关的动态资源:任何用户访问该资源都会得到相同的内容,但该内容可能在任意时间发生变化,如博客文章。
只有“用户无关的动态资源”适合应用 micro-caching 缓存策略。
安装依赖:
npm i lru-cache
server.js
const express = require('express')
const fs = require('fs')
const { createBundleRenderer } = require('vue-server-renderer')
const setupDevServer = require('./build/setup-dev-server')
const LRU = require('lru-cache')
const cache = new LRU({
max: 100,
maxAge: 10000 // Important: entries expires after 1 second.
})
const isCacheable = req => {
console.log(req.url)
if (req.url === '/posts') {
return true
}
}
const server = express()
server.use('/dist', express.static('./dist'))
const isProd = process.env.NODE_ENV === 'production'
let renderer
let onReady
if (isProd) {
const serverBundle = require('./dist/vue-ssr-server-bundle.json')
const template = fs.readFileSync('./index.template.html', 'utf-8')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
renderer = createBundleRenderer(serverBundle, {
template,
clientManifest
})
} else {
// 开发模式 -> 监视打包构建 -> 重新生成 Renderer 渲染器
onReady = setupDevServer(server, (serverBundle, template, clientManifest) => {
renderer = createBundleRenderer(serverBundle, {
template,
clientManifest
})
})
}
const render = async (req, res) => {
try {
const cacheable = isCacheable(req)
if (cacheable) {
const html = cache.get(req.url)
if (html) {
return res.end(html)
}
}
const html = await renderer.renderToString({
title: '拉勾教育',
meta: `
<meta name="description" content="拉勾教育">
`,
url: req.url
})
res.setHeader('Content-Type', 'text/html; charset=utf8')
res.end(html)
if (cacheable) {
cache.set(req.url, html)
}
} catch (err) {
res.status(500).end('Internal Server Error.')
}
}
// 服务端路由设置为 *,意味着所有的路由都会进入这里
server.get('*', isProd
? render
: async (req, res) => {
// 等待有了 Renderer 渲染器以后,调用 render 进行渲染
await onReady
render(req, res)
}
)
server.listen(3000, () => {
console.log('server running at port 3000.')
})
Gzip 压缩
注意事项:
- 默认的过滤器功能使用 compressible 模块来确定 res.getHeader(’Content-Type’)是否可压缩。