vue-ssr的实现原理连载(一)
前言:
服务端渲染,简明的说就是在服务端获取数据并进行解析渲染,直接生成html片段返回给浏览器。
优缺点:
服务端渲染能解决的问题: 1.SEO问题,前端动态渲染的内容是不能被搜索蜘蛛抓取的。2.首屏加载过程慢。SPA在初始化首屏的时候需要加载所有的资源,这也是使用服务端渲染能折中解决的问题。
服务端渲染的缺点:1.增加服务器的压力。 2.同构似乎对前后端分离有所违背
vue-server-renderer
文档地址: https://ssr.vuejs.org/en/ 暂时没有中文文档。下面来一步一步的说明实现过程。所有的源码都可以在我github上查看,并且根据教程分了step,欢迎star。
vue-ssr的实现原理连载(一): https://github.com/Jasonwang911/vue-ssr/tree/master/step1
首先安装相关依赖:
npm init -y yarn add koa koa-router koa-static vue vue-router vuex vue-server-renderer
先要确定vue的版本
vue & vue-server-renderer 2.3.0+ vue-router 2.5.0+ vue-loader 12.0.0+ & vue-style-loader 3.0.0+
vue-server-renderer 是vue官方用来实现vue服务端渲染的一个包。具体官方教程是: https://ssr.vuejs.org/zh/#%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E6%B8%B2%E6%9F%93-ssr-%EF%BC%9F
新建server.js文件,然后编写一个最简单的koa服务
const Koa = require("koa"); const Router = require("koa-router"); const Static = require("koa-static"); const app = new Koa(); const router = new Router(); router.get("/", ctx => { ctx.body = "hello vue-ssr"; }); app.use(router.routes()); app.listen(3000, () => { console.log(`node serve run at port 3000`); });
使用nodemon启动 nodemon server.js, 打开浏览器的 localhost:3000端口,可以看到 hello vue-ssr。
接下来,我们来进行一些改造,引入vue, 来创建一个vue的实例,然后引入 vue-server-renderer ,来去渲染我们的vue实例。这里需要注意两点, 1. 创建的vue的实例是在服务端使用的,所以并不能挂载元素,只能渲染template模板字符串 2. vue-server-renderer 这个包可以帮我们创建一个渲染器render, 渲染器有很多方法 render.renderToString() 渲染成字符串,render.renderToStream 渲染成流等等。需要注意的是 render.renderToString() 接收一个vue的实例并返回一个promise的字符串,将返回的字符串直接渲染到页面上,注意这个方法是个异步操作。
const Koa = require("koa"); const Router = require("koa-router"); const Static = require("koa-static"); const Vue = require("vue"); const VueServerRender = require("vue-server-renderer"); // 创建一个vue的实例,注意在服务端不能挂载元素,只能使用渲染模板字符串 const vm = new Vue({ data() { return { msg: "hello vue-ssr" }; }, template: `<div>{{msg}}</div>` }); // 创建一个渲染器 let render = VueServerRender.createRenderer(); const app = new Koa(); const router = new Router(); // render.renderToString() 接收一个vue的实例并返回一个promise的字符串,将返回的字符串直接渲染到页面上,注意这个方法是个异步操作 router.get("/", async ctx => { ctx.body = await render.renderToString(vm); }); app.use(router.routes()); app.listen(3000, () => { console.log(`node serve run at port 3000`); });
<div data-server-rendered="true">hello vue-ssr</div>
data-server-rendered="true" 的作用会在后面的小结说明,是为了性能的考虑,告诉浏览器这个是服务端渲染的,不需要进行diff操作,以节省性能的目的。
查看完源代码,你可能会说,这个缺少一个基本的html的页面结构,现在我们就来一起实现:
首先,render渲染函数可以接受参数,参数中的template便是模板,我们可以将render.renderToString(vm)的结果插入到模板中的指定位置中去。这个指定位置是通过一个注释标明的,首先我们建立模板文件 template.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>vue-ssr</title> </head> <body> <!-- vue-ssr-outlet --> </body> </html>
<!-- vue-ssr-outlet --> 就是标明服务端渲染后的字符串 <div data-server-rendered="true">hello vue-ssr</div> 将要插入的位置。
然后我们在koa服务中读取模板文件,并在渲染函数中配置这个模板文件,读取模板文件使用了node的fs模块:
const fs = require("fs"); const template = fs.readFileSync("./template.html", "utf8");
完整代码:
server.js
const Koa = require("koa"); const Router = require("koa-router"); const fs = require("fs"); const Static = require("koa-static"); const Vue = require("vue"); const VueServerRender = require("vue-server-renderer"); // 创建一个vue的实例,注意在服务端不能挂载元素,只能使用渲染模板字符串 const vm = new Vue({ data() { return { msg: "hello vue-ssr" }; }, template: `<div>{{msg}}</div>` }); const template = fs.readFileSync("./template.html", "utf8"); // 创建一个渲染器 let render = VueServerRender.createRenderer({ template }); const app = new Koa(); const router = new Router(); // render.renderToString() 接收一个vue的实例并返回一个promise的字符串,将返回的字符串直接渲染到页面上,注意这个方法是个异步操作 router.get("/", async ctx => { ctx.body = await render.renderToString(vm); }); app.use(router.routes()); app.listen(3000, () => { console.log(`node serve run at port 3000`); });
template.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>vue-ssr</title> </head> <body> <!--vue-ssr-outlet--> </body> </html>
第一部分就到这里。