vue ssr 实现方式(学习笔记)


Posted in Javascript onJanuary 18, 2019

为什么要写本文呢,话说现在vue-ssr 官网上对 vue 服务端渲染的介绍已经很全面了,包括各种服务端渲染框架比如 Nuxt.js 、 集成 Koa 和vue-server-renderer 的 node.js 框架 egg.js,都有自己的官网和团队在维护,文档真是面面俱到功能强大,但是,我个人在刚开始看这些资料的时候,总是忍不住发起灵魂三问:“我是谁?我在哪?我在干什么?”,提前没有相关知识的人开始学这些,肯定是要走一些弯路或者卡在某个点一段时间的,所以我想把我的学习经验做下总结,一方面方便自己以后查阅,一方面也会在文中加一些针对官网上没有细说的点的理解,希望能帮助你减少些学习成本,毕竟这是一个知识共享的时代嘛。本文不涉及到源码解析,主要讲解如何实现 vue 的服务端渲染,比较适合 vue-ssr 小白阅读,下面我们进入正文:

先说下基本概念:

ssr 的全称是 server side render,服务端渲染,vue ssr 的意思就是在服务端进行 vue 的渲染,直接对前端返回带有数据,并且是渲染好的HTML页面;而不是返回一个空的HTML页面,再由vue 通过异步请求来获取数据,再重新补充到页面中。

这么做的最主要原因,就是搜索引擎优化,也就是SEO,这更利于网络爬虫去爬取和收集数据。

为什么这样就有利于网络爬虫爬取呢?

这里简单说一下爬虫的爬取方式,爬虫通过访问 URL 获取一个页面后,会获取当前HTML中已存在的数据,也可以理解为把拿到的 HTML 页面转为了字符串内容,然后解析、存储这些内容,但是如果页面中有些数据是通过异步请求获得的,那么爬虫是不会等待异步请求返回之后才结束对页面数据的解析的,这样就会没有爬取到这部分数据,很不利于其他搜索引擎的收录。

这也就是为什么单页面网站是不具备良好的SEO效果的,因为单页面返回的就是一个基本为空的 HTML 文件,里面就一个带有ID的元素等待挂载而已,页面的内容都是通过 js 后续生成的,比如这样:

<!DOCTYPE html>
<html lang="en">
 <head><title>Hello</title></head>
 <body><div id="app"></div></body>
 <script src="bundle.js"></script>
</html>

但对于很多公司来说,公司的产品是希望能被百度、谷歌等搜索引擎收录之后,进行排名,进一步的被用户搜索到,能更利于品牌的推广、流量变现等操作,要实现这些,就必须保证产品的网页是能够被网络爬虫爬取到的,显然一个完整的带有全部数据的页面更利于爬虫的爬取,当然现在也有很多方法可以去实现针对页面异步数据的爬取,github 上也开源了很多的爬虫代码,但是这显然对于爬虫来说更加的不友好、成本更高。

SSR 当然也是有着其他的好处的,比如首屏页面加载速度更快,用户等待时间更短等,其他更多概念可以查看官网 https://ssr.vuejs.org/zh/ ,这些官网上都有介绍。

代码实现

下面我们结合官网上的代码,做一下代码实操,来加深下理解:

在官网中,提供了一个使用模块 vue-server-renderer 简单实现 vue 服务端渲染的示例:

新建一个文件夹vue-ssr-demo,进入其中执行如下命令:

// 安装模块 
npm install vue vue-server-renderer --save

创建文件 server.js

// vue-ssr-demo/server.js 示例代码

//第一步,创建vue实例
const Vue = require('vue');
const app = new Vue({
 template: "<div>hello world</div>"
});

//第二步,创建一个renderer
const renderer = require('vue-server-renderer').createRenderer();
//第三步,将vue渲染为HTML
renderer.renderToString(app, (err, html)=>{
 if(err){
  throw err;
 }
 console.log(html);
});

保存以上代码后,在 vue-ssr-demo 文件夹下打开命令行工具,执行 node server.js 命令,可得到如下 HTML 内容:

➜ vue-ssr-demo node server.js
<div data-server-rendered="true">hello world</div>

好,上面的例子中我们已经让 vue 在服务端,也就是 node 环境下运行起来了,到这里其实已经实现了 vue 的服务端渲染了。

可是,实际项目中使用哪有这么简单,起码数据还没渲染啊,那接下来我们看看如何渲染数据:

vue-ssr 渲染数据的方式有两种,我们先看下第一种:

// server.js
const data_vue = {
 word: 'Hello World!'
};
//第一步,创建vue实例
const Vue = require('vue');
//vue 实例化过程中插入数据
const app = new Vue({
 data: data_vue,
 template: "<div>{{word}}</div>"
});

//第二步,创建一个renderer
const renderer = require('vue-server-renderer').createRenderer();

//第三步,将vue渲染为HTML
renderer.renderToString(app, (err, html)=>{
 if(err){
  throw err;
 }
 console.log(html);
});

第一种方式,在创建 vue 实例时,将需要的数据传入 vue 的模板,使用方法与客户端 vue 一样;运行 server.js 结果如下,数据 data_vue 已经插入到 vue 模板里面了:

➜ vue-ssr-demo node server.js
<div data-server-rendered="true">Hello World!</div>

第二种,模板插值,这里我们也直接先放代码:

const data_vue = {
 word: 'Hello World!'
};
const data_tpl = {
 people: 'Hello People!'
};
//第一步,创建vue实例
const Vue = require('vue');
const app = new Vue({
 data: data_vue,
 template: "<div>{{word}}</div>"
});

//第二步,创建一个 renderer 实例
const renderer = require('vue-server-renderer').createRenderer({
 template: "<!--vue-ssr-outlet--><div>{{people}}</div>"
});

//第三步,将vue渲染为HTML
renderer.renderToString(app, data_tpl, (err, html)=>{
 if(err){
  throw err;
 }
 console.log(html);
});

这里我们增加了数据 data_tpl,你会发现,在 renderToString 方法中传入了这个参数,那么这个参数作用在哪里呢?这就要看下官网中关于 createRenderer 和 renderToString 方法的介绍了,

createRenderer: 使用(可选的)选项创建一个 Renderer 实例。
const { createRenderer } = require('vue-server-renderer')
const renderer = createRenderer({ / 选项 / })

在选项中,就有一个参数叫 template,看官网怎么说的:

template: 为整个页面的 HTML 提供一个模板。此模板应包含注释 <!--vue-ssr-outlet-->,作为渲染应用程序内容的占位符。
为整个页面的 HTML 提供一个模板。此模板应包含注释 <!--vue-ssr-outlet-->,作为渲染应用程序内容的占位符。

模板还支持使用渲染上下文 (render context) 进行基本插值:

使用双花括号 (double-mustache) 进行 HTML 转义插值 (HTML-escaped interpolation);

使用三花括号 (triple-mustache) 进行 HTML 不转义插值 (non-HTML-escaped interpolation)。

根据介绍,在创建 renderer 实例时,可以通过 template 参数声明一个模板,这个模板用来干嘛呢?就用来挂载 vue 模板渲染完成之后生成的 HTML。这里要注意一下,当创建 renderer 实例时没有声明 template 参数,那么默认渲染完就是 vue 模板生成的 HTML;当创建 renderer 实例时声明了 template 参数,一定要在模板中增加一句注释 “<!--vue-ssr-outlet-->” 作为 vue 模板插入的占位符,否则会报找不到插入模板位置的错误。

再次运行 server.js ,结果如下,vue 模板已成功插入,且 template 模板中的 {{people}} 变量也因在 renderToString 方法中第二位参数的传入,显示了数据:

vue-ssr-demo node server.js
<div data-server-rendered="true">Hello World!</div><div>Hello People!</div>

如果我们把 template 换成一个 HTML 页面的基本架构,来包裹 vue 模板,是不是就能得到一个完整页面了呢?我们来试一下:

const data_vue = {
 word: 'Hello World!'
};
const data_tpl = {
 people: 'Hello People!'
};
//第一步,创建vue实例
const Vue = require('vue');
const app = new Vue({
 data: data_vue,
 template: "<div>{{word}}</div>"
});

//第二步,创建一个renderer
const renderer = require('vue-server-renderer').createRenderer({
 template: `<!DOCTYPE html>
 <html lang="en">
  <head><title>Hello</title></head>
  <body>
  <!--vue-ssr-outlet--><div>{{people}}</div>
  </body>
 </html>`
});

//第三步,将vue渲染为HTML
renderer.renderToString(app, data_tpl, (err, html)=>{
 if(err){
  throw err;
 }
 console.log(html);
});

运行 server.js ,结果如下,我们得到了一个完整的 HTML 页面,且成功插入了数据:

vue-ssr-demo node server.js
<!DOCTYPE html>
<html lang="en">
  <head><title>Hello</title></head>
  <body>
  <div data-server-rendered="true">Hello World!</div><div>Hello People!</div>
  </body>
</html>

好,现在页面生成了,该怎么显示呢?这里我们借助下框架 Koa 实现,先来安装:

npm install koa -S

然后修改 server.js ,如下:

const data_vue = {
 word: 'Hello World!'
};
const data_tpl = {
 people: 'Hello People!'
};

const Koa = require('koa');
//创建 koa 实例
const koa = new Koa();

const Vue = require('vue');

//创建一个renderer
const renderer = require('vue-server-renderer').createRenderer({
 template: `<!DOCTYPE html>
 <html lang="en">
  <head><title>Hello</title></head>
  <body>
  <!--vue-ssr-outlet--><div>{{people}}</div>
  </body>
 </html>`
});

// 对于任何请求,app将调用该异步函数处理请求:
koa.use(async (ctx, next) => {
 // await next();
 
 //创建vue实例
 const app = new Vue({
  data: data_vue,
  template: "<div>{{word}}</div>"
 });

 //将vue渲染为HTML
 const body = await renderer.renderToString(app, data_tpl);
 ctx.body = body;
});

// 在端口3001监听:
koa.listen(3001);
console.log('app started at port 3001...');

运行 server.js :

vue-ssr-demo node server.js
app started at port 3001...

然后打开浏览器,输入网址 http://localhost:3001/ ,即可看到运行后的效果。

这样就实现了一个简单的服务端渲染项目,但是我们在平常开发的时候,肯定不会这么简单的去构建一个项目,必然会用到一些,比如打包、压缩的工具,这篇就写到这里,下一篇我们尝试使用 webpack 来构建一个 vue 的服务端渲染项目。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
解决ExtJS在chrome或火狐中正常显示在ie中不显示的浏览器兼容问题
Jan 11 Javascript
js的2种继承方式详解
Mar 04 Javascript
jquery和css3实现的炫酷时尚的菜单导航
Sep 01 Javascript
jquery获取及设置outerhtml的方法
Mar 09 Javascript
JS实现仿腾讯微博无刷新删除微博效果代码
Oct 16 Javascript
JS实现JSON.stringify的实例代码讲解
Feb 07 Javascript
详谈jQuery unbind 删除绑定事件 / 移除标签方法
Mar 02 Javascript
angularjs实现猜数字大小功能
May 20 Javascript
vue中使用refs定位dom出现undefined的解决方法
Dec 21 Javascript
vue通过style或者class改变样式的实例代码
Oct 30 Javascript
vue中使用codemirror的实例详解
Nov 01 Javascript
Vue 打包的静态文件不能直接运行的原因及解决办法
Nov 19 Vue.js
JS实现的贪吃蛇游戏完整实例
Jan 18 #Javascript
jquery的$().each和$.each的区别
Jan 18 #jQuery
使用form-create动态生成vue自定义组件和嵌套表单组件
Jan 18 #Javascript
jquery层次选择器的介绍
Jan 18 #jQuery
js实现图片放大并跟随鼠标移动特效
Jan 18 #Javascript
vue.js的双向数据绑定Object.defineProperty方法的神奇之处
Jan 18 #Javascript
jQuery无冲突模式详解
Jan 17 #jQuery
You might like
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
php 使用redis锁限制并发访问类示例
2016/11/02 PHP
从JavaScript 到 JQuery (1)学习小结
2009/02/12 Javascript
JS对象转换为Jquery对象实现代码
2013/12/29 Javascript
一个通过script自定义属性传递配置参数的方法
2014/09/15 Javascript
BootStrap框架中的data-[ ]自定义属性理解(推荐)
2017/02/14 Javascript
Vue单页面应用保证F5强刷不清空数据的解决方案
2018/01/31 Javascript
Vue.js 中的 v-cloak 指令及使用详解
2018/11/19 Javascript
详解Puppeteer前端自动化测试实践
2019/02/21 Javascript
vue router 传参获取不到的解决方式
2019/11/13 Javascript
vue使用recorder.js实现录音功能
2019/11/22 Javascript
在vue中axios设置timeout超时的操作
2020/09/04 Javascript
[02:55]2018DOTA2国际邀请赛勇士令状不朽珍藏Ⅲ饰品一览
2018/08/01 DOTA
linux平台使用Python制作BT种子并获取BT种子信息的方法
2017/01/20 Python
简单谈谈python中的语句和语法
2017/08/10 Python
浅谈python和C语言混编的几种方式(推荐)
2017/09/27 Python
Python图像处理之gif动态图的解析与合成操作详解
2018/12/30 Python
Python调用C语言的实现
2019/07/26 Python
详解如何获取localStorage最大存储大小的方法
2020/05/21 HTML / CSS
西班牙伏林航空公司:Vueling
2016/08/05 全球购物
澳大利亚网上书店:QBD
2021/01/09 全球购物
园林施工员岗位职责
2013/12/11 职场文书
八年级英语教学反思
2014/01/09 职场文书
教育技术学专业职业规划书
2014/03/03 职场文书
服务之星事迹材料
2014/05/03 职场文书
法定代表人授权委托书范文
2014/09/22 职场文书
2014年医院工作总结
2014/11/20 职场文书
起诉离婚协议书样本
2014/11/25 职场文书
检讨书范文300字
2015/01/28 职场文书
团委工作总结2015
2015/04/02 职场文书
2016年“节能宣传周”活动总结
2016/04/05 职场文书
MySQL一些常用高级SQL语句
2021/07/03 MySQL
MySQL七大JOIN的具体使用
2022/02/28 MySQL
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
2022/04/19 Java/Android
Python可视化神器pyecharts绘制水球图
2022/07/07 Python
win10输入法不见了只能打出字母怎么解决?
2022/08/05 数码科技