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 相关文章推荐
Jquery为单选框checkbox绑定单击click事件
Dec 18 Javascript
node.js中的buffer.copy方法使用说明
Dec 14 Javascript
JavaScript取得键盘按下方向键是哪个的方法
Aug 04 Javascript
使用Node.js处理前端代码文件的编码问题
Feb 16 Javascript
关于angularJs指令的Scope(作用域)介绍
Oct 25 Javascript
bootstrapValidator.min.js表单验证插件
Feb 09 Javascript
Angular在一个页面中使用两个ng-app的方法
Feb 20 Javascript
js es6系列教程 - 新的类语法实战选项卡(详解)
Sep 02 Javascript
javascript修改浏览器title方法 JS动态修改浏览器标题
Nov 30 Javascript
微信小程序实现全局搜索代码高亮的示例
Mar 30 Javascript
创建echart多个联动的示例代码
Nov 23 Javascript
vue swipe自定义组件实现轮播效果
Jul 03 Javascript
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
PHP cURL获取微信公众号access_token的实例
2018/04/28 PHP
PHP设计模式之数据访问对象模式(DAO)原理与用法实例分析
2019/12/12 PHP
动态控制Table的js代码
2007/03/07 Javascript
jquery插件制作 手风琴Panel效果实现
2012/08/17 Javascript
jQuery获取当前对象标签名称的方法
2014/02/07 Javascript
基于JavaScript实现仿京东图片轮播效果
2015/11/06 Javascript
js实现图片轮播效果
2015/12/19 Javascript
jQuery插件imgPreviewQs实现上传图片预览
2016/01/15 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
使用jQuery调用XML实现无刷新即时聊天
2016/08/07 Javascript
js 实现获取name 相同的页面元素并循环遍历的方法
2017/02/14 Javascript
JS去掉字符串前后空格或去掉所有空格的用法
2017/03/25 Javascript
微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
2017/04/18 Javascript
微信小程序中上传图片并进行压缩的实现代码
2018/08/28 Javascript
vue遍历生成的输入框 绑定及修改值示例
2019/10/30 Javascript
vue随机验证码组件的封装实现
2020/02/19 Javascript
[01:30]我们共输赢 完美世界城市挑战赛开启全新赛季
2019/04/19 DOTA
[44:40]KG vs LGD 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
[04:05]TI9战队采访 - Natus Vincere
2019/08/22 DOTA
python益智游戏计算汉诺塔问题示例
2014/03/05 Python
Python写的PHPMyAdmin暴力破解工具代码
2014/08/06 Python
Python 中的Selenium异常处理实例代码
2018/05/03 Python
python自动化报告的输出用例详解
2018/05/30 Python
Python使用Beautiful Soup爬取豆瓣音乐排行榜过程解析
2019/08/15 Python
django-利用session机制实现唯一登录的例子
2020/03/16 Python
python使用openpyxl操作excel的方法步骤
2020/05/28 Python
HTML5中的postMessage API基本使用教程
2016/05/20 HTML / CSS
针对HTML5的Web Worker使用攻略
2015/07/12 HTML / CSS
Mytheresa美国官网:德国知名的女性奢侈品电商
2017/05/27 全球购物
MSC邮轮官方网站:加勒比海、地中海和世界各地的假期
2018/08/27 全球购物
销售实习自我鉴定
2013/12/07 职场文书
《北大荒的秋天》教学反思
2014/04/14 职场文书
小学生操行评语
2014/04/22 职场文书
大学新闻系应届生求职信
2014/06/02 职场文书
2014年小学国庆节活动方案
2014/09/16 职场文书
中班下学期个人工作总结
2015/02/12 职场文书