干货基于Vue的前后端分离实践

Posted 移动Labs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货基于Vue的前后端分离实践相关的知识,希望对你有一定的参考价值。

前言:中移苏研公有云产品组对当前主流的前端解决方案进行横向对比,并结合目前组内资源情况,确定了使用Vue.js进行前后端分离的前端解决方案。本文将介绍Vue.js的相关知识,以及如何利用Vue.js做前后端分离的。

Vue简介



Vue(读音 /vjuː/,类似于 view)是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue也完全能够为复杂的单页应用提供驱动。

【干货】基于Vue的前后端分离实践


Vue近年来之所以非常的火爆,在前端工程师中迅速圈了一大批粉丝的原因来自于其渐进式框架的设计定位。Vue的生态虽然能够覆盖上图所有的功能,但对于开发者来说,我们并不需要一开始就掌握上图提及的所有功能。因为Vue框架本身只提供了核心的声明式渲染以及组件系统,其他的路由,大规模状态管理,构建系统都由插件的形式提供,且插件之间相互独立,无依赖。这对于开发者来说,是一个相当灵活的设计,可插拔的组件设计能够节省大量学习成本,对于人手不足,工期紧张的团队来说,Vue无疑是非常具有吸引力的前端解决方案。


Vue与其他框架对比


如下图列出了当前主流的框架,框架所涵盖的内容从少到多排列,这里的多少并不是用来评判框架的好坏,而是框架所提供的核心功能的多少。

【干货】基于Vue的前后端分离实践

  • 纯模板引擎:只负责管理状态到界面的映射。

  •  React和Vue: 专注于组件系统,以及状态到界面的映射。

  • Backbone: 更进一步,提供了MVC架构,指导用户分层。

  • Angular: 前端MVC框架,提供了一站式的封装,包含路由等一系列功能。

  • Ember: Ember的设计理念是约定优于配置,为用户设计打包好一切,开发者只需开箱即用。

  • Meteor: Meteor更进一步,他包揽了前后端,从前台页面到操作数据库,全都集成。


通过以上的比较我们可以得出这样的结论:涵盖内容少的框架不一定就比包揽一切的框架差,而是来源于开发者的取舍。框架做得少可以带来更多的灵活性,但同时也带来一定地选择问题,因为对于同一功能,少的框架可能存在多个第三方的解决方案;框架做得多带来的是更强的侵入性,更高地学习成本,以及更低的灵活性。这就意味着,选择做得多的框架,对于某个功能,你只能采用框架提供的解决方案,而失去了选择更优方案的机会。


我们在对主流框架进行对比之后,最终选择了Vue作为此次前后端分离改造的前端框架,原因无外乎以下几点:

  • 足够轻量高效

    Vue在提供强大的组件系统和声明式渲染的前提下,其核心库库只有20kb min+gzip大小,采用Virtual Dom,相较于直接操作DOM,其速度大为提升。

  •  足够灵活

    Vue的生态圈非常丰富,其他框架有的功能,生态圈中总有一款适合你,可插拔性极高。

  •  足够易用

    一个初级的前端工程师,也能在短期之内快速上手,非常适合团队存在新人的场景


Vue全家桶


Vue本身提供了核心的声明式渲染和组件系统, 而对于常用的路由,状态管理、构建工具,Vue官方也提供了一站式的解决方案,我们称之为Vue全家桶。接下来我们将从Vue全家桶入手,介绍Vue的核心概念。


1

声明式渲染

【干货】基于Vue的前后端分离实践

目前主流框架都是采用函数式到状态的映射来操作DOM,DOM状态只是数据状态的一个映射。我们只需将逻辑放在状态的层面,当状态改变时,视图会在框架的帮助下自动更新到所需状态,从而避免了传统的监测数据改动然后手动操作DOM。


那么Vue是如何操作的呢?Vue提供了一个语法模板,Vue的编译器会将这些写好的模板编译成渲染函数,当函数被调用时就会渲染并且返回一个虚拟DOM树,然后由Vue引擎的patch函数将虚拟DOM树映射成真是的DOM。在这个过程中,Vue的响应式监测系统将监测渲染过程中所依赖的数据来源,从而精确感知数据源的变动。当数据发生变动后,会通知重新渲染,生成一颗新的虚拟DOM树,Vue引擎会将新树与老树进行对比,得到最小改动去操作DOM,达到了局部刷新,降低操作资源,提高性能的效果。下图展示了Vue是如何执行上述操作的示例图:

【干货】基于Vue的前后端分离实践


2

状态管理

在进行大型项目开发的时候,如果手动维护数据状态这是一个不可想象的事情。首先,数据传参在多层嵌套组件中传递非常繁琐,并且对于兄弟组件传参无能为力。另外,我们经常会使用到父子组件直接引用或者通过事件来变更和同步状态的多份拷贝,这种开发模式非常脆弱,通常会导致代码无法维护。因此,Vue官方借鉴了Flux、Redux和 The Elm Architecture的思想,提供了集中式存储管理插件-Vuex,用来为Vue.js应用提供状态管理模式,同时Vue官方的Devtools中支持查看Vuex的数据状态变化。下图为使用Vue组件跟Vuex配合使用的模式图:

【干货】基于Vue的前后端分离实践

图中所示的State,Mutations,以及Actions是Vuex的核心,接下来我们将简单的介绍下这三个概念:


State


Vuex使用单一状态树来包含全部的应用层级状态,每个应用仅包含一个store实例,开发者可以从store实例中读取数据的状态。简单点理解就是,store是我们获取vuex其他属性的唯一句柄。

【干货】基于Vue的前后端分离实践


上面的代码片段,展示了通常在Vue组件中获取vuex中的数据状态。通过在计算属性中获取状态,每当数据状态store.state.count发生变化时,计算属性便会重新计算,并且触发更新关联DOM。


Mutation


在Vuex中,更改数据状态的唯一方式就是提交mutation,mutation非常类似于事件,每个mutation都有一个事件类型和一个回调函数,回调函数第一个参数就是state,从而我们可以在回调函数中进行状态变更:

【干货】基于Vue的前后端分离实践


Action


Action可以理解为动作,一般在Action中执行异步操作(例如:获取数据)、提交Mutation,action接受store是的的上下文信息context对象,从而可以调用context来commit一个mutation。

【干货】基于Vue的前后端分离实践


实践中,我们通常使用ES2015的参数解构来简化代码,特别是在需要多次调用commit的时候:

【干货】基于Vue的前后端分离实践


3

组件系统

Vue组件化系统与其他主流框架的组件化道路核心思想是一致的,都是将UI结构映射到恰当的组件树,如下图所示:

【干货】基于Vue的前后端分离实践

通过组件,我们可以更好的划分UI界面,有利于代码复用与团队协作。在Vue中,父组件通过props单向传递给子组件进行通信,子组件可以通过emit向父组件触发事件,这样就形成了Vue的基本父子通信模式。

【干货】基于Vue的前后端分离实践

在实际的开发实践中,我们通常会将组件分为几类:


Global component


Global component-全局组件,顾名思义就是会广泛应用于系统的各个部分,例如导航条组件,弹出框组件等。这些组件的特点就是嵌套于根组件,不隶属于某个View。当与vuex配合使用时,应单独的使用state中的一个module,这个state中的数据专门用来控制全局组件的逻辑操作,不应当和其他业务Module混用。其他组件如果希望改变global component,可以使用commit一个mutation来进行操作。


Simple component


Simple component-简单组件,属于Vue的传统组件,一般涉及到的交互和数据都不多,只起到简单展示、拆分父组件的作用。这种组件一般通过使用props来传递数据,emit触发事件传递给父组件。


Complex component


Complex component-复杂组件,通常包含很多交互逻辑,展示数据多而复杂,以及可能需要直接访问API接口。对于这种组件,建议必须采用结合vuex来进行通信,跳过父组件,直接在组件内部进行Mutation的派发。因为,采用props以及emit的方式带来的必将是难以维护的黑洞。


4

路由

路由相信大家都非常熟悉,当做一个界面复杂度非常高的应用时,会涉及到众多的页面,手动管理页面显然已经不合时宜。因此,需要有路由工具来将URL与组件树做映射,将这些关系声明式地对应起来。

【干货】基于Vue的前后端分离实践


当然,类似于上图的路由关系,我们可以通过hash去模拟生成简单路由。但事实上,客户端路由涉及到更多复杂的问题,而Vue官方给开发者提供了一个强大的客户端路由插件:vue-router,它可以做到除了路由以外更强大的功能,具体如下:

  • 嵌套路由

  • 具名路由

  • 多个平级路由出口

  • 复杂匹配规则

  • 跳转动画

  • 跳转规则限制

  • 滚动条行为

  • 懒加载

  • 重定向/别名

等等,以上的功能如果都由自己去匹配,无疑会带来更高的复杂度。


我们的解决方案

1

前端架构

公有云产品组涉及到的前端工程种类大致可以分为两种:1. 门户展示、产品订购。 2. 产品控制台、用户中心。 对于这两类工程,有着一个显著的区别,门户类是对外展示的主体,涉及到许多展示的页面,对于SEO有着非常高的要求;而控制台产品属于私密数据,不需要对搜索引擎开放。针对这两种场景,我们采用了两种解决方案:


SPA


SPA全称为Single Page Application,也就是单页面应用。目前的主流架构,Angular、Vue等默认提供的就是SPA的方式。这种方式有几个比较显著的特点:

  1. 所有页面的渲染都在一个Web页面。

  2. 通过Ajax与后台交互数据。

  3. 具备较好的分层理念,前端工程化。

通过Vue Cli脚手架工具我们可以快速的生成一个SPA项目:

【干货】基于Vue的前后端分离实践


通过上面的命令,我们就可以起一个基于Vue的SPA项目了。当然我们在官方的CLI生成项目中做了一些自己的改造,简单的列举部分如下:

  1. 集成Vuex, Vue router。

  2. 集成store2库作为storage操作库。

  3. 集成axios作为Ajax基础工具库。

  4. 引入scss作为css预编译语言。

  5. 集成Element UI,并集成自定义主题。

  6. 集成Echarts。

  7. 集成font-awesome图标库。

  8. 编写常用操作库文件以及自动化部署脚本。

除了上面的8条,我们还集成了其他一些常用的组件库。对于这种SPA架构,我们将其用于控制台项目。


SSR


SSR全程为Server Side Render,及服务器端渲染。刚才我们也提到了,门户对SEO有着较高的要求。SPA已经不适合这样的场景了,原因很简单,因为SPA的所有页面都是通过JS动态渲染的,数据也是异步的,搜索引擎通过URL获取到的网页内容就是一段框架页面代码,而没有其他的页面代码。虽然某些搜索引擎是可以支持抓取异步数据,但是国内的主流搜索引擎还是不支持的。因此必须采用一种技术使得搜索引擎通过URL获取到的是整个页面加载完后的样式,SSR就是官方推荐的解决方案,它的优点如下:

  • 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。

  • 更快的内容到达时间(time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。

    无需等待所有的 javascript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。通常可以产生更好的用户体验,并且对于那些「内容到达时间(time-to-content)与转化率直接相关」的应用程序而言,服务器端渲染(SSR)至关重要。


当然,采用SSR之前也必须要做权衡,因为SSR会带来更多的服务器端负载。SSR需要在服务器端启动一个基于Node的server,相对于SPA的静态页面,无疑需要占用更多的内存和计算资源。因此,对于比较简单的SEO,我们推荐使用webpack的预渲染技术来实现,这样代价相对小很多。


Vue官方提供了一套服务端渲染的解决方案,具体的就是引入vue-server-renderer插件,然后结合webpack以及express服务器等来达到SSR的目的。但是,官方的解决方案,复杂度相对来说还是比较高的,且实际写代码带来的复杂度有一定量的提升。对于经验缺乏的新手,在此我们不建议采用官方的解决方案,而是采用第三方的框架:Nuxt.js。


Nuxt.js非常易上手,基于最新的Vue版本进行了封装,因此兼容Vue全部语法,并集成了Vue全家桶,可以说开箱即用。而且,Nuxt.js提供了快捷的项目模板,只需几个命令,一个项目即可生成:

【干货】基于Vue的前后端分离实践


而我们在门户类的应用中,也是基于此架构进行的深度定制。


2

API网关

【干货】基于Vue的前后端分离实践


前后端分离之后,相对于原有的前后端一体的开发模式,前端现在与后端交互的是API,目前后台API通常都是采用微服务的形式进行提供。当使用微服务构建整个API服务时,一般会有许多职责不同的应用在运行着,这些应用会需要一些通用的功能,例如鉴权、流量控制、监控、日志统计等。在传统的单体应用中,这些功能一般都是内嵌在应用中,作为一个组件运行。但是在微服务模式下,不同种类且独立运行的应用可能会有数十甚至数百种,继续使用这种方式会造成非常高的管理和发布成本,因此使用API网关就非常有必要了,API网关的职责大致可以归纳为两类:

  • 对服务应用有感知且重要的功能,例如鉴权。

  • 对服务应用无感知的边缘服务,例如流量控制、监控、页面级缓存等。

因此,我们在进行前后端分离的同时,也开始了API网关技术的研发,目前我们采用的Netflix的zuul架构来构建我们的网关,并结合目前的CAS做了服务鉴权,基本能保证目前的需求。当然,我们还结合Haproxy,nginx等来对我们的前后端应用进行了负载均衡和高可用的设计,限于篇幅原因,这里就不再展开。


小结

在本文中,我们介绍了Vue框架,并将其与其他主流框架进行了简单的对比。然后针对两种不同类型的应用,介绍了两种不同的前端架构方案,并在最后,简单的介绍了配套API网关的方案。以上是共有云产品组试水前后端分离的第一版解决方案,明年我们将继续推进老系统的前后端分离改造,并将结合容器,自动化运维等技术,进一步深化目前的解决方案。


往期精选:




以上是关于干货基于Vue的前后端分离实践的主要内容,如果未能解决你的问题,请参考以下文章

前端大讲堂基于Vue的前后端分离实践

技术干货网易视频云前后端分离实践

前后端分离实践:基于vue实现网站前台的权限管理

前后端分离实践:基于vue实现网站前台的权限管理

再谈前后端分离丨趣店前端团队基于 koajs 的前后端分离实践

VueThink是一套基于Vue全家桶+ Thinkphp的前后端分离框架