尽管 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 rendererlet onReadyif (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 onReadyrender(req, res)})server.listen(3000, () => {console.log('server running at port 3000.')})
Gzip 压缩
注意事项:
- 默认的过滤器功能使用 compressible 模块来确定 res.getHeader(’Content-Type’)是否可压缩。
