vue 服务端渲染(一):初探
2020-09-30 本文已影响0人
梦想成真213
概念
- 客户端渲染:在浏览器端进行渲染,服务端返回的只是 <div id="app"></div> 的空标签文档;
- 服务端渲染:在服务器就做好数据的的拼接,请求返回的 html 是完整的文档。
客户端渲染,服务端渲染对比
- 客户端渲染不利于 SEO 搜索引擎优化(返回的是空标签);
- 服务端渲染出来的文档可以被爬虫抓取,客户端异步渲染很难被爬虫抓取;
- 服务端渲染直接将 HTML 字符串传递给浏览器,大大加快了首屏加载时间;
- 服务端渲染占用更多的 CPU 和内存资源;
- 在服务端渲染模式下,一些常用的浏览器 API 可能无法正常使用(服务端没有 document,window);
- 服务端渲染只支持 vue 中 beforeCreate 和 created 两个生命周期(因为没有 dom,所以不涉及 mounted 等)
SSR 运行过程:
- 服务端渲染只是做首屏的渲染;
- 后续在浏览器中的路由切换逻辑执行的是客户端渲染(前端路由切换页面,每个路由返回的首屏是服务端来做)
- 服务端渲染使用 Node 服务来实现(前后端分离模式)
- 传统的服务端渲染是 jsp asp php+smarty,不适合前后端分离开发模式
整个打包过程
- 首先要保证客户端渲染模式下可以跑起来,然后提供一个服务端入口
- 通过将一份代码打包出来两份逻辑(客户端和服务端)
- 前端拿到打包出来的 bandle.js,后端通过打包的结果渲染出字符串返回给浏览器
-
浏览器展示 = 前端 bundle.js + 服务端渲染的字符串
如下图:展示了打包过程:
安装包
- vue vue-server-renderer(通过vue-server-renderer来实现vue的服务端渲染)
- koa koa-router(通过 node 来做服务端)
npm install vue vue-server-renderer koa @koa/router -D
开发中
本地新建一个文件夹 vue-ssr-demo,初始化项目npm init -f
,生成一个package.json,npm install
安装需要用到的包,新建一个server.js
来启动服务:
// server.js
const Vue = require('vue')
const VueServerRenderer = require('vue-server-renderer')
const vm = new Vue({
data() {
return {
name: '小可爱',
age: 3
}
},
template: `<div>我是:{{name}},{{age}}岁</div>`
})
const Koa = require('koa')
const Router = require('@koa/router')
// 创建一个渲染器
const render = VueServerRenderer.createRenderer()// 创建一个渲染器
let app = new Koa() // app实例
let router = new Router() // 路由实例
router.get('/', async (ctx) => {
ctx.body = await render.renderToString(vm) // render.renderToString 返回的是一个promise
})
app.use(router.routes())
app.listen(3500)
启动命令:nodemon server.js
,VueServerRenderer.createRenderer()创建一个渲染器,调用渲染器 renderToString
方法 传入vm实例
,访问http://localhost:3500/ 可以看到页面展示:
页面上显示了
data-server-rendered="true"
表示服务端渲染。
通常我们都是有一个 html 模板,然后将打包的内容放进去,新建一个 html 文件,写下vue server
的标记
<!--vue-ssr-outlet-->
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vue ssr template</title>
</head>
<body>
<!--vue-ssr-outlet-->
</body>
</html>
server.js
中读取本地的index.html
文件,文件内容作为渲染器模板即可:
const Vue = require('vue')
const VueServerRenderer = require('vue-server-renderer')
const vm = new Vue({
data() {
return {
name: '小可爱',
age: 3
}
},
template: `<div>我是:{{name}},{{age}}岁</div>`
})
const Koa = require('koa')
const Router = require('@koa/router')
const fs = require('fs')
const path = require('path')
const htmlStr = fs.readFileSync(path.resolve(__dirname, 'index.html'), 'utf8') // 同步读取文件
// 创建一个渲染器
const render = VueServerRenderer.createRenderer({
// 可以从本地读取html文件当作模板
template: htmlStr, // 采用哪个模版去渲染,在html中加入这个<!--vue-ssr-outlet-->标签表示渲染到这个位置上
}) // 创建一个渲染器
let app = new Koa() // app实例
let router = new Router() // 路由实例
router.get('/', async (ctx) => {
// ctx.body = 'hello world'
ctx.body = await render.renderToString(vm) // render.renderToString 返回的是一个promise
// // <div data-server-rendered="true">我是:hcj,20岁</div>
})
app.use(router.routes())
app.listen(3500)
监听文件改动,自动重启服务
npm install nodemon -g
目前实现了一个最简单的 ssr,后续文章加入客户端配置,服务端配置,vue-router, vuex 来实现完整的 ssr。
github:https://github.com/mxcz213/vue-ssr-demo/tree/part-one