vue-ssr性能优化:
-
减少服务端渲染DOM数:
- 1.结合vue的插槽系统、内置component组件的is,利用vue ssr服务端只会执行beforeCreate和created生命周期的特性,封装自定义组件,该组件在mounted的时候将包裹的组件挂载到component组件的js属性上。
- 2.vue高级异步组件封装延迟加载方法,只有当模块到达指定可视区域时在加载。
-
开启多进程。node.js是单进程,单线程模型。
-
开启缓存:
- 1.页面级缓存:在创建render实例时利用LRU-Cache来缓存当前请求的资源。
附上我这边的代码吧,比较懒,全粘贴上去了哈哈哈:
- 1.页面级缓存:在创建render实例时利用LRU-Cache来缓存当前请求的资源。
const fs = require('fs')
const path = require('path')
const LRU = require('lru-cache')
const express = require('express')
const favicon = require('serve-favicon')
const compression = require('compression')
const microcache = require('route-cache')
const resolve = file => path.resolve(__dirname, file)
const { createBundleRenderer } = require('vue-server-renderer')
const isProd = process.env.NODE_ENV === 'production'
const useMicroCache = process.env.MICRO_CACHE !== 'false'
const serverInfo =
`express/${require('express/package.json').version} ` +
`vue-server-renderer/${require('vue-server-renderer/package.json').version} `
const app = express()
function createRenderer(bundle, options) {
return createBundleRenderer(bundle, Object.assign(options, {
// 组件级别缓存
cache: LRU({
max: 1000,
maxAge: 1000 * 60 * 15
}),
basedir: resolve('./dist'),
runInNewContext: false
}))
}
let renderer
let readyPromise
const templatePath = resolve('./src/index.html')
if(isProd) {
const template = fs.readFileSync(templatePath, 'utf-8')
const bundle = require('./dist/vue-ssr-server-bundle.json')
const clientManifest = require('./dist/vue-ssr-client-manifest.json')
renderer = createRenderer(bundle, {
template,
clientManifest
})
} else {
readyPromise = require('./build/setup-dev-server')(
app,
templatePath,
(bundle, options) => {
renderer = createRenderer(bundle, options)
}
)
}
const serve = (path, cache) => express.static(resolve(path), {
maxAge: cache && isProd ? 1000 * 60 * 60 * 24 *30 : 0
})
app.use(compression({ threshold: 0 }))
app.use(favicon('./public/logo.png'))
app.use('/dist', serve('./dist', true))
app.use('/public', serve('./public', true))
app.use('/manifest.json', serve('./manifest.json', true))
app.use(microcache.cacheSeconds(1, req => useMicroCache && req.originalUrl))
function render(req, res) {
const s = Date.now()
res.setHeader("Content-Type", "text/html")
res.setHeader("Server", serverInfo)
const handleError = err => {
if(err.url) {
res.redirect(err.url)
} else if(err.code === 404) {
res.status(404).send('404 | Page Not Found')
} else {
res.status(500).send('500 | Internal Server Error')
console.error(`error during render : ${req.url}`)
console.error(err.stack)
}
}
const context = {
title: 'SSR-hahahahahha', // default title
meta: `
<meta name="theme-color" content="#4285f4">
`,
url: req.url
}
renderer.renderToString(context, (err, html) => {
if(err) {
return handleError(err)
}
res.send(html)
if(!isProd) {
console.log(`whole request: ${Date.now() - s} ms`)
}
})
}
app.get('*', isProd ? render : (req, res) => {
readyPromise.then(() => render(req, res))
})
app.listen(8000,()=>{
console.log("server running at http://127.0.0.1:8000")
})
// app.set('port', process.env.PORT || 8888)
// let hostname = '0.0.0.0'
// app.listen(app.get('port'), hostname, () => {
// console.log(`Server running at http://${hostname}:${app.get('port')}`)
// })
- 2.组件级缓存:可缓存组件必须定义一个唯一的name选项。通过使用唯一的名称,每个缓存键cache key对应一个组件。如果render在组件渲染过程中进行缓存命中,那么它将直接重新使用整个子树的缓存结果。
- 3.分布式缓存:SSR应用程序部署在多服务、多进程下,进程下的缓存并不是共享的,造成缓存命中率低下。可以采用如redis,用以实现多进程间对缓存的共享。
参考文章:SSR同构降级策略