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 相关文章推荐
JavaScript使用技巧精萃[代码非常实用]
Nov 21 Javascript
基于jquery的内容循环滚动小模块(仿新浪微博未登录首页滚动微博显示)
Mar 28 Javascript
javascript实现在某个元素上阻止鼠标右键事件的方法和实例
Aug 12 Javascript
js实现Select头像选择实时预览代码
Aug 17 Javascript
jQuery中deferred对象使用方法详解
Jul 14 Javascript
一个极为简单的requirejs实现方法
Oct 20 Javascript
通过命令行创建vue项目的方法
Jul 20 Javascript
微信小程序实现换肤功能
Mar 14 Javascript
基于vue框架手写一个notify插件实现通知功能的方法
Mar 31 Javascript
支付宝小程序实现省市区三级联动
Jun 21 Javascript
纯js+css实现在线时钟
Aug 18 Javascript
原生JS实现弹幕效果的简单操作指南
Nov 10 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 header()函数使用详细(301、404等错误设置)
2013/04/17 PHP
codeigniter上传图片不能正确识别图片类型问题解决方法
2014/07/25 PHP
php实现QQ空间获取当前用户的用户名并生成图片
2015/07/25 PHP
摘自织梦CMS的HTTP文件下载类
2015/08/08 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
thinkphp5框架结合mysql实现微信登录和自定义分享链接与图文功能示例
2019/08/13 PHP
jquery 插件开发备注
2010/08/27 Javascript
jQuery.clean使用方法及思路分析
2013/01/07 Javascript
JS获取地址栏参数的几种方法小结
2014/02/28 Javascript
利用原生js和jQuery实现单选框的勾选和取消操作的方法
2016/09/04 Javascript
JSON 数据详解及实例代码分析
2017/01/20 Javascript
js实现5秒倒计时重新发送短信功能
2017/02/05 Javascript
PyQt5利用QPainter绘制各种图形的实例
2017/10/19 Python
TensorFlow实现创建分类器
2018/02/06 Python
Python元组常见操作示例
2019/02/19 Python
Python 模拟动态产生字母验证码图片功能
2019/12/24 Python
Python OpenCV去除字母后面的杂线操作
2020/07/05 Python
如何在mac下配置python虚拟环境
2020/07/06 Python
css3高级选择器使用方法
2013/12/02 HTML / CSS
松本清官方海外旗舰店:日本最大的药妆连锁店
2017/11/21 全球购物
蛋白质世界:Protein World
2017/11/23 全球购物
Topman美国官网:英国著名的国际平价时尚男装品牌
2017/12/22 全球购物
施华洛世奇美国官网:SWAROVSKI美国
2018/02/08 全球购物
StubHub中国:购买和出售全球活动门票
2020/01/01 全球购物
飞利浦美国官网:Philips美国
2020/02/28 全球购物
管理建议书范文
2014/05/13 职场文书
信电学院毕业生自荐书
2014/05/24 职场文书
2014年班组工作总结
2014/11/20 职场文书
2014年就业工作总结
2014/11/26 职场文书
2015年艾滋病防治工作总结
2015/05/22 职场文书
你真的了解PHP中的引用符号(&)吗
2021/05/12 PHP
vue Element-ui表格实现树形结构表格
2021/06/07 Vue.js
使用python+pygame开发消消乐游戏附完整源码
2021/06/10 Python
pandas中关于apply+lambda的应用
2022/02/28 Python
九大龙王魂骨,山龙王留下躯干骨,榜首死的最憋屈(被捏碎)
2022/03/18 国漫