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 相关文章推荐
自己使用js/jquery写的一个定制对话框控件
May 02 Javascript
jQuery控制Div拖拽效果完整实例分析
Apr 15 Javascript
浅谈javascript实现八大排序
Apr 27 Javascript
javascript组合使用构造函数模式和原型模式实例
Jun 04 Javascript
使用AmplifyJS组件配合JavaScript进行编程的指南
Jul 28 Javascript
jQuery EasyUI 布局之动态添加tabs标签页
Nov 18 Javascript
BootStrap Datepicker 插件修改为默认中文的实现方法
Feb 10 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
Sep 19 jQuery
Angular之toDoList的实现代码示例
Dec 02 Javascript
Node.js创建Web、TCP服务器
Dec 05 Javascript
vue加载自定义的js文件方法
Mar 13 Javascript
vite2.0+vue3移动端项目实战详解
Mar 03 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
77A一级收信机修理记
2021/03/02 无线电
深入PHP empty(),isset(),is_null()的实例测试详解
2013/06/06 PHP
PHP的curl实现get,post和cookie(实例介绍)
2013/06/17 PHP
PHP实现的英文名字全拼随机排号脚本
2014/07/04 PHP
php实现window平台的checkdnsrr函数
2015/05/27 PHP
PHP的PDO常用类库实例分析
2016/04/07 PHP
PHP读取zip文件的方法示例
2016/11/17 PHP
JQuery FlexiGrid的asp.net完美解决方案 dotNetFlexGrid-.Net原生的异步表格控件
2010/09/12 Javascript
javascript跨域刷新实现代码
2011/01/01 Javascript
JQuery 自定义CircleAnimation,Animate方法学习笔记
2011/07/10 Javascript
jQuery实现简单的间隔向上滚动效果
2015/03/09 Javascript
jq实现左侧显示图片右侧文字滑动切换效果
2015/08/04 Javascript
jquery validate表单验证的基本用法入门
2016/01/18 Javascript
基于jquery实现无限级树形菜单
2016/03/22 Javascript
微信小程序之批量上传并压缩图片的实例代码
2018/07/05 Javascript
vue设置全局访问接口API地址操作
2020/08/14 Javascript
[03:54]DOTA2英雄梦之声_第06期_昆卡
2014/06/23 DOTA
python使用opencv读取图片的实例
2017/08/17 Python
python使用正则表达式替换匹配成功的组
2017/11/17 Python
Tensorflow卷积神经网络实例
2018/05/24 Python
Python Pandas数据中对时间的操作
2019/07/30 Python
PyQt5+Caffe+Opencv搭建人脸识别登录界面
2019/08/28 Python
Python 格式化打印json数据方法(展开状态)
2020/02/27 Python
python程序文件扩展名知识点详解
2020/02/27 Python
python else语句在循环中的运用详解
2020/07/06 Python
css3+伪元素实现鼠标移入时下划线向两边展开的效果
2017/04/25 HTML / CSS
纽约家具、家居装饰和地毯店:ABC Carpet & Home
2017/06/21 全球购物
印尼太阳百货公司网站:Matahari
2018/02/04 全球购物
定制别致的瑜伽垫:Sugarmat
2019/06/21 全球购物
部队领导证婚词
2014/01/12 职场文书
服务标兵事迹材料
2014/05/04 职场文书
打架检讨书
2015/01/27 职场文书
教师年度考核自我评鉴
2015/08/11 职场文书
MySQL如何构建数据表索引
2021/05/13 MySQL
sql中mod()函数取余数的用法
2021/05/29 SQL Server
python图像处理基本操作总结(PIL库、Matplotlib及Numpy)
2021/06/08 Python