服务端渲染(SSR)
知识储备
- Vue
- ES6
- webpack
SPA越来越无法满足业务对页面响应速度的要求。随着工程不断变大,打包文件不断增长,页面的整体刷新加载速度慢慢成为瓶颈。
越来越多的应用开始使用SSR来提高响应速度。
服务端渲染VS客户端渲染
- 何为渲染?
如果我们只是想显示一堆不变的数据,那么我们直接写一个a.html丢到服务器上让客户端访问就可以了。
但这是基本不可能的事情,数据一般是变化的。
你不可能为每套数据写一个视图,所以我们需要分离数据和视图,然后使用一种技术将数据塞到视图中,这种技术就叫渲染。
这工作放在服务器上做就是服务器渲染,放在浏览器做就是浏览器渲染。
简单来说:渲染,就是指 数据 放入 html模板文档的过程。
- 客户端渲染:html页面作为静态文件存在,前端请求时后端不对该文件做任何内容上的修改,直接以资源的方式返回给前端,前端拿到页面后,根据写在html页面上的js代码,对该html的内容进行修改。
- 服务端渲染:前端发出请求后,后端在将HTML页面返回给前端之前,先把HTML页面中的特定区域,用数据填充好,再将完整的HTML返回给前端。在SPA场景下,服务端渲染都是针对第一次get请求,它会完整的html给浏览器,浏览器直接渲染出首屏,用不着浏览器端多一个AJAX请求去获取数据再渲染。
为什么使用服务器端渲染
优点:
- 更好的 SEO,因为传统的搜索引擎只会从 HTML 中抓取数据,这会导致前端渲染的页面无法被抓取。
- 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备 。页面首屏时间大概有80%消耗在网络上,剩下的时间在后端读取数据以及浏览器渲染,显然要优化后面的20%是比较困难的,优化网络时间是效果最明显的手段。传统的Ajax请求是先请求js再由js发起数据请求,两项时间再加上浏览器渲染时间才是首屏时间。而SSR能将两个请求合并为一个。
缺点:
- 更多的服务器端负载。
- 服务器端和浏览器环境差异带来的问题,例如document等对象找不到的问题。
为什么服务端渲染有利于SEO
首先我们需要明白一点,SEO
并不是一项技术,而是一种针对搜索引擎的策略,它的目的的让搜索引擎的爬虫,更快,更准确的爬取到我们开发的网站。
如果我们有人写过爬虫的话,那么会了解,我们的爬虫爬取的其实是网页里的标签内容,通过获取这些内容进行分析。假设我们的网站都是采用前后端分离进行开发,界面都需要用js去请求接口,等到接口返回之后才展示真个界面。那么我们的爬虫也需根本获取不到我们想要的内容。
而通过服务渲染,服务端将整个界面的数据填充完整之后,直接返回这个界面。第一,少了客户端请求的过程。第二,返回的直接就是整个界面。必然使爬虫能够更快,更准确的爬取到它想要的信息。
如何选择
建议:如果注重SEO的站点,非强交互的页面,建议用SSR;像后台管理页面这类强交互的应用,建议使用前端渲染。
前端+服务器端渲染跟原来的jsp有什么不同
不同的地方很多很多,关键点就是前后端为什么要分离,分离之后有什么好处。
前后端分离后,专业的人做专业的事,后端负责提供数据,前端负责做界面、写交互。前端的环境基本上就是node,以webpack + koa、express + 三大框架 + babel为核心进行开发。
分离之后,好处就是:
- 前后端服务分别部署,不需要改个字就重新发布一堆jar包了
- 分离后,前端的工作就不受后端的束缚了,开发时的热更新、热替换;babel、core-js、typescript可以让开发者无需在浏览器兼容方面下太多功夫,会自动将新语法编译成旧语法;编译生产环境代码时自动压缩css、js代码,压缩图片,文件地址注入,文件自动上传cdn等;组件化开发,复用的功能不需要像以前一样每个页面引一堆js了;异步加载代码,在执行功能时加载js文件;eslint,开发时实时检查代码风格
- ssr的话,就是浏览器请求node服务,node服务去请求数据,或者直接ajax去请求接口,这里边的性能损耗比起开发时不方便,是完全可以接受的。而且用三大框架开发,只操作数据,对比以前拿到数据后还要手动更新dom节点来说,方便了很多,代码量也少了不少,代码都是复用的,一端编写,两端执行
1. Nuxt.js服务器端渲染
学习目标
- 了解Nuxt.js的作用
- 掌握Nuxt.js中的路由
- 掌握layouts、pages以及components的区别
- Nuxt的生命周期
- 能够在Nuxt.js项目中使用element-ui
- 掌握Nuxt.js中异步获取数据的方式
- 完成小项目
- 掌握SEO的优化
1.1 Nuxt.js入门
1.1.1 什么是Nuxt.js
Vue服务端渲染官网
Nuxt.js官网
Nuxt.js 是一个基于 Vue.js 的通用应用框架。
1.1.2 创建Nuxt项目
npm i create-nuxt-app -g
create-nuxt-app my-nuxt-demo
cd my-nuxt-demo
npm run dev
1.1.3 文件结构分析
└─my-nuxt-demo
├─.nuxt // Nuxt自动生成,临时的用于编辑的文件,build
├─assets // 用于组织未编译的静态资源如LESS、SASS或JavaScript,对于不需要通过 Webpack 处理的静态资源文件,可以放置在 static 目录中
├─components // 用于自己编写的Vue组件,比如日历组件、分页组件
├─layouts // 布局目录,用于组织应用的布局组件,不可更改⭐
├─middleware // 用于存放中间件
├─node_modules
├─pages // 用于组织应用的路由及视图,Nuxt.js根据该目录结构自动生成对应的路由配置,文件名不可更改⭐
├─plugins // 用于组织那些需要在 根vue.js应用 实例化之前需要运行的 Javascript 插件。
├─static // 用于存放应用的静态文件,此类文件不会被 Nuxt.js 调用 Webpack 进行构建编译处理。服务器启动的时候,该目录下的文件会映射至应用的根路径 / 下。文件夹名不可更改。⭐
└─store // 用于组织应用的Vuex 状态管理。文件夹名不可更改。⭐
├─.editorconfig // 开发工具格式配置
├─.eslintrc.js // ESLint的配置文件,用于检查代码格式
├─.gitignore // 配置git忽略文件
├─nuxt.config.js // 用于组织Nuxt.js 应用的个性化配置,以便覆盖默认配置。文件名不可更改。⭐
├─package-lock.json // npm自动生成,用于帮助package的统一设置的,yarn也有相同的操作
├─package.json // npm 包管理配置文件
├─README.md
1.2 页面和路由
1.2.1 基本路由
Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置。
假设 pages 的目录结构如下
└─pages
├─index.vue
└─user
├─index.vue
├─one.vue
那么,Nuxt.js 自动生成的路由配置如下:
router: {
routes: [
{
name: 'index',
path: '/',
component: 'pages/index.vue'
},
{
name: 'user',
path: '/user',
component: 'pages/user/index.vue'
},
{
name: 'user-one',
path: '/user/one',
component: 'pages/user/one.vue'
}
]
}
1.2.2 页面跳转
- 不要写成a标签,因为是重新获取一个新的页面,并不是SPA
<nuxt-link to="/users"></nuxt-link>
- this.$router.push(‘/users’)
1.2.3 动态路由
- 在 Nuxt.js 里面定义带参数的动态路由,需要创建对应的以下划线作为前缀的 Vue 文件 或 目录。
- 获取动态参数{{$route.params.id}}
1.2.4 路由参数校验
Nuxt.js 可以让你在动态路由对应的页面组件中配置一个validate方法用于校验动态路由参数的有效性。该函数有一个布尔类型的返回值,如果返回true则表示校验通过,如果返回false则表示校验未通过。
validate(data) {
cosole.log(data)
return true
}
1.2.5 嵌套路由
- 添加一个Vue文件,作为父组件
- 添加一个与父组件同名的文件夹来存放子视图组件
- 在父文件中,添加组件,用于展示匹配到的子视图
1.2.6.自定义路由配置
想要自定义配置路由,需要现在根目录上创建一个 nuxt.config.js 的配置文件,nuxtJS会根据这个配置文件中的配置信息来自动配置我们的服务器和项目相关的内容。例如在配置文件中写入:
/**
* Nuxt.js配置文件
*/
module.exports = {
router: {
base: '/abc', // 创建到服务器的哪个文件夹下
/**
* 扩展路由
* @param {Array} routes 一个数组,路由配置表,也就是我们项目的路由列表
* @param {Function} resolve 解析路由组件路径
*/
extendRoutes (routes, resolve) {
routes.push({
path: '/hello',
name: 'hello',
component: resolve(__dirname, 'pages/hello.vue')
})
}
}
}
这样就可以将/abc作为我们项目的根目录,并且扩展一个hello的路由。我们可以来访问一下:
1.3 layouts & pages & components
1.3.1 布局目录layout
- 去layouts文件夹下面新建一个新的layout组件,例如teachers.vue,并在这个组件中添加组件,这样,所有和teachers相关的页面都会有公共的layout
- 需要用到teachers.vue的组件添加layout属性,并指定需要使用的layout,例如:layout: ‘teachers’
pages中不同的页面需要不同的个性化布局这时候layout就起作用了
layouts 根目录下的所有文件都属于个性化布局文件,可以在页面组件中利用 layout 属性来引用。
pages文件下组件的layout属性值为layout 文件下的所对应的布局组件的名称
请确保在布局文件里面增加 组件用于显示页面非布局内容。
1.3.2 页面目录pages
页面目录pages用于组织应用的路由及视图。Nuxt.js框架读取该目录下所有的.vue文件并自动生成对应的路由配置。页面组件实际上是Vue组件,只不过Nuxt.js为这些组件添加了一些特殊的配置项(对应的Nuxt.js提供的功能特性)以便快速开发通用应用。
1.3.3 组件目录components
在components文件夹下面新建一个Header.vue组件 引入组件,注意路径的~符号,表示根目录 layout中也能使用组件
组件目录components用于组织应用的vue.js组件。Nuxt.js不会扩展增强该目录下vue.js组件,即这些组件不会像页面组件那样有asyncData方法的特性。
1.3.4 样式配置
nuxt.config.js中设置全局css样式的文件路径
1.4 生命周期
1.5 ElementUI使用
- 下载npm i element-ui -S
- 在plugins文件夹下面,创建ElementUI.js文件
import Vue from 'vue'
import ElementUI from 'element-ui'
Vue.use(ElementUI)
- 在nuxt.config.js中添加配置
css: [
'element-ui/lib/theme-chalk/index.css'
],
plugins: [
{src: '~/plugins/ElementUI', ssr: true }
],
build: {
vendor: ['element-ui']
}
1.6 异步数据
asyncData 方法
Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,,使得我们可以在设置组件的数据之前能异步获取或处理数据。asyncData 方法会在组件(限于页面组件)每次加载 之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的 上下文对象,你可以利用 asyncData 方法来获取数据,Nuxt.js 会将 asyncData 返回的数据融合组件 data 方法 返回的数据一并返回给当前组件。
注意:由于 asyncData 方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例 对象。
<template>
<div>
修改用户信息{{id}},名称:{{name}}
</div>
</template>
<script>
export default{
layout:'test',
//根据id查询用户信息
asyncData(){
console.log("async方法")
return {
name:'程序员'
}
},
data(){
return {
id:''
}
},
mounted(){
this.id = this.$route.params.id;
}
}
</script>
<style>
</style>