vivo商城前端架构升级

Wesley13
• 阅读 965

本文首发于 vivo互联网技术 微信公众号
链接: https://mp.weixin.qq.com/s/vD9yvYNaxTQBLABik6aqNg
作者:官网商城前端团队

【背景】

一年前 vivo 商城还是以 Java 为技术核心,前后台一起,Java 既要负责服务、数据库,也要负责页面的渲染。在早期这种开发模式也能够很好的运行。然而随着业务迭代的加快,前端技术的发展,这种开发模式的弊端越来越明显。主要突出的有以下两个方面:

  • 前端技术栈架构繁杂且陈旧,导致迭代速度很难提升

到2018年12月,整个商城前端系统随着不同需求叠加积累的原因,造成了不同页面使用不同的技术,比较典型的有jQuery,Vue,FreeMarker,artTemplate,这些不同的技术栈从开发来看,相同的内容,在不同的页面可能使用不同的技术栈,导致需要开发很多遍,对开发、测试来说工作量都是成倍的增长。

  • 无法适用多端开发的需求

自2017年微信上线小程序功能后,各种小程序如雨后春笋般出现,vivo 商城一开始也推出了自己的微信小程序,然而由于业务发展,需要适配的端越来越多,原先使用原生开发的小程序方式,无法做到一套代码编到多个平台。

为了提升开发效率,满足高速发展的业务需求,在过去的一年里,我们通过对商城内外部系统的全面分析,按照分层的逻辑整理出前端架构的升级指导说明。

【分层架构】

在《前端架构-从入门到微前端》一书中提到,前端架构自上而下可以设计为四个层次,分别为系统级、应用级、模块级、代码级,我们通过这四个层次来分析vivo商城前端架构升级过程中的种种思考和实践,最终形成了一套以Vue + Node.js为核心的全端架构方案。

技术演进过程:

vivo商城前端架构升级

分层架构实施图:

vivo商城前端架构升级

一、系统级

即应用在整个系统内的关系,比如如何和后台通讯,如何与其他应用集成。针对这一级别,我们进行了前后端分离、多端统一、BFF、SSR等方面的探索和实践。

1、前后端分离

架构升级,第一步面临的问题便是前后端分离,vivo 商城仍然处于业务高速发展时期,不能因为技术重构而停下业务版本的迭代, 因此业务版本迭代必须要和前后端分离同时进行,那怎么才能做到双线并行,平滑升级?

这里举个小例子:当我们分离完成订单模块后,就会通过 Nginx 将关于订单模块的所有请求转发到新的静态资源服务上,如下图:

vivo商城前端架构升级

通过前后端分离,我们彻底解放前端,让前端开发效率提升了至少2个档次。

更多技术细节比如:新老页面如何同步信息,如何容灾容错等等,请关注我们的系列第二篇《vivo商城前端架构升级(二):前后端分离篇》

2、多端统一

从 PC 浏览器,到移动端浏览器、到 App 内嵌,再到各个小程序,再到服务端、客户端。繁荣的生态,犹如百家争鸣,百花齐放。然而,繁荣的背后,对前端工程师的挑战,则与日俱增。

我们承接的端越来越多,新的端不断的出现,如小程序、快应用等。前端工程师陷入了如下套娃陷阱:

  1. 现有代码、新代码要适配新的端开发场景
  2. 已经适配新的端开发场景的代码成为了现有代码
  3. 现有代码、新代码要适配新的端开发场景
  4. 循环...

我们希望解决这种问题,希望做到一套技术架构方案【代码】,可以覆盖现在的端和未来的端。

通俗点说,我们希望做到如下图所示的能力:

vivo商城前端架构升级

在这种前端开发背景下,多端统一出现了。它是前端的一个未来趋势,它也是解决上面套娃陷阱的一剂良药。

更多细节内容,请关注我们的系列第三篇《vivo商城前端架构升级(三):多端实践篇》

3、BFF

  • 业务现状

随着端的增多,新的接口数量呈现爆发式增长,老的接口为了适配各端,也会增加了各种不同的字段,导致前后端适配多端的工作量越来越大。但是抽象来看,大部分端的变动都是UI层级的变动,很少有底层服务的改变,所以带来了一个问题接口究竟是面向UI,还是面向通用服务?

为了解决这个问题,Sam Newman 发表了一篇文章,讲述了这种体验者专用 API 的方式,并将其称为BFFBackends for Frontends)模式。

BFF理念中,最重要的一点是:服务自治,谁使用谁开发。服务自治减少了沟通成本,带来了灵活和高效。

  • 关键技术

商城前端积极适应前端技术的发展,为了提供一流的用户体验,积极推动BFF层在商城业务中的实现。

vivo商城前端架构升级

  • 直连Dubbo:

Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

我们使用了社区提供的 Dubbo2.js 进行 Dubbo 服务的调用,并且做了一些封装来优化发开体验。

vivo商城前端架构升级

  • 集成GraphQL网关:

GraphQL 是一个开源的 API 数据查询和操作语言及实现为了实现上述操作的相应运行环境。相较于REST以及其他 web service架构提供了一种高效、强大和灵活的开发 web APIs的方式。

(1)请求你所要的数据 不多不少

vivo商城前端架构升级

(2)获取多个资源 只用一个请求

vivo商城前端架构升级

(3)强大的API调试工具

vivo商城前端架构升级

4、SSR

自从前后端分离后,前端采用了SPA技术,走的都是CSR(客户端渲染)的模式。使用CSR的优势在于节省后端资源、局部刷新等,但随着应用的日益复杂,首屏渲染时间不断变长, 并且存在严重的 SEO 问题。所以为了解决SPA应用遇到的这些问题, 我们必须考虑 SSR。

SSR 即服务端渲染,是指由服务器端完成页面的HTML 结构拼接,并且直接将拼接好的HTML发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的处理技术。

vivo商城前端架构升级

主要优势在于:

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

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

为了避免重复造轮子,我们使用了社区非常优秀的SSR框架nuxt,通过一系列的优化,比如:页面缓存、组件缓存、API缓存、最小化渲染等方式,最终让我们页面在500ms内就能全部展示,这是用户体验上的极大提升。

二、应用级

即应用外部的整体架构,如多个应用之间如何共享组件、如何通信、如何开发通用脚手架等。在应用级别的架构上面,我们主要沉淀了适用于商城的UI库,为其他商城衍生项目提供基础组件支持。

1、组件库

移动端的设计千变万化,市场上非常流行的移动端的组件库比如antd-mobile , vant,他们对于开发通用型的 App,非常高效且美观,然而大部分自主研发的 App都有自己的一套设计风格和理论。如果使用流行的组件库,就会出现频繁需要修改源码,以适应UI风格的变化。这样的工作量日积月累,就会变得越来越大。所以我们还是建议如果是做自己特色的App,还是要自建UI库。如果感觉自建UI库难度较大,可以先fork一份流行的组件库,学习其中的各种实现,慢慢形成自己的UI库

商城也实现了自己的UI库,目前已经在商城、秒杀、vivo 内购、v客联盟等应用中广泛使用,极大的提高了开发效率。如下图:

vivo商城前端架构升级

三、模块级

应用内部的模块架构,如代码的模块化、数据和状态的管理等,在项目中比较典型的是我们设计了针对 Vue 的极致模块化方案,顶层 page 设计,数据自治等方面的工作。

1、极致模块化

我们的方案摈弃了官方推荐的按文件类型组织模块,而采用按照功能组织模块,这种"可插拔式"组件设计,让代码按照功能聚合。

vivo商城前端架构升级

一个文件包里面包含该功能的所有实现,包括图片、样式、脚本、数据流、组件等等,这样另一个项目想要使用,直接迁移即可,极大地减少了迁移的成本,并且还有一个优势是,如果这个功能以后下架,直接删除即可,不必各个文件夹下找文件,极大地提升了代码的简洁性和可维护性。

➜  confirm git:(dev_abtest_gray) tree 
.
├── api.js     // 接口资源
├── components // 内部组件
│   ├── component1
│   │   ├── images
│   │   ├── index.scss
│   │   └── index.vue
│   ├── component2
├── images   // 图片资源
├── index.scss // 样式资源
├── index.vue  // 逻辑实现
├── module.js  // 数据流
└── trackData.js // 埋点

2、顶层 page 设计

所有的页面都会有很多通用的功能,比如加载前的骨架图、出错后的处理逻辑、数据采集逻辑、上拉刷新、下滑分页加载,全局 iOS 适配等等,这些功能在逻辑上是需要抽象的,避免各个页面多次实现,导致浪费开发资源和降低程序的可维护性。

针对此我们实现了一个顶级 page 组件,所有的页面都继承于这个 page 。做到通用性的功能全局管理。

顶级 page 的部分 API 使用如下:

<template>
  <v-page
    // 页面是否完成
    :pageInit="true"
    // 页面是否出错
    :pageError="false"
    // 页面监控开启,包括pv,uv,渲染时间
    :pageMonitor="true"
    // 上拉刷新
    @pullDownRefresh="pullDownRefresh"
    // 下拉监听
    @reachBottom="reachBottom"
    // 滚动监听
    @pageScroll="pageScroll"
  >
    <template slot="header">
      <!-- 自定义头部,如果没有则使用默认顶部导航菜单 -->
      <Header />
    </template>
    <template slot="skeleton">
      <!-- 自己实现的骨架图,如果没有则使用默认骨架图-->
      <Skeleton />
    </template>
    <template slot="footer">
      <!-- 自己实现的底部,吸底显示,如果没有则不显示-->
      <Footer />
    </template>
  </v-page>
</template>

3、数据自治

本着谁使用,谁负责的原则,对于页面中的数据流也是一样的,我们开发了针对page的全局mixin,负责自动注册和卸载页面数据,并将各个页面之间的数据进行隔离。

import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'

export default (name, module) => ({
  computed: {
    ...mapState(name, Object.keys(module.state)),
    ...mapGetters(name, Object.keys(module.getters))
  },
  created () {
    // todo 要加判断是否已经注册,动态注册模块
    if (!(name in this.$store._modules.root._children)) {
      this.$store.registerModule(name, module)
    }
  },
  methods: {
    ...mapActions(name, Object.keys(module.actions)),
    ...mapMutations(name, Object.keys(module.mutations))
  }
})

四、代码级

当我们开始编写代码的时候,就要考虑代码的规范和质量。规范的目的是为了提升维护性,而质量则是开发的门面,一个好的项目离不开这这两个内容的约束。

1、规范

一个好的规范应该做到简单、好记、易于执行。为了实现这个目标,我们制定了一系列的规范,最主要的是开发规范、提交规范

每个项目组的规范可能都不一样,需要根据自己的项目特色,可以参考优秀的项目实践,整理出自己的项目规范,小组内部讨论优化,达成一致意见,最后发布执行。每一位新进项目组的成员,首先要做的就是学习这些规范,用规范引导开发。

(1)开发规范

包含但不局限于以下内容:命名规范、HTML 规范、css规范、js规范。

(2)提交规范:

为了规范提交代码,从而方便开发者追踪项目的开发信息和功能特性,我们封装了**@vivo/commit**,对我们的提交进行强制校验。比如:

vivo商城前端架构升级

每一条commit由四个部分组成,如下图:

vivo商城前端架构升级

  • 修改类型

style: 样式修改

fix: bug修复

feat: 功能开发

refactor: 代码重构

test: 测试类修改

doc: 文档更新

conf: 配置修改

merge: 代码合并

  • 影响模块

每一条commit,应明确指出其影响范围是哪个模块,如果是通用模块,注释上(全局)字样,方便code reviewer对方案进行评估

  • 跟踪单号

每一条commit,必须要有单号,每个公司都有自己的缺陷跟踪系统,单号的目的是为了让每一条提交有据可循,方便后续对问题的回溯。

  • 问题描述

问题描述应该简洁明了,让其他人一看就知道这条commit修改了什么,禁用一些通用描述,比如:'修改了一个bug','添加了一个功能'

2、质量

关于质量我们从两个方面进行提升,代码检视 和 代码覆盖率

(1)代码检视:

为了提高代码检视的效率,调研了市场上面众多的代码检视工具,好用都需要收费,并且功能比较复杂,比如:upsource。于是开发了一个基础vscodecode review插件,支持GitLab,实时消息通知。

添加评论

vivo商城前端架构升级

(2)代码覆盖率:

商城的业务迭代速度非常快,使得开发单元测试开发的成本非常大,然而我们有时又想看看测试场景的覆盖情况,为了实现这些目标,我们研发了集成测试代码覆盖率平台。通过这个平台可以清晰的看到每一行代码被测试执行的情况。保证了开发的质量,并能给测试提供精确的指导建议。

  • 服务端架构

vivo商城前端架构升级

  • 前台架构

vivo商城前端架构升级

  • 自动集成 GitLab

vivo商城前端架构升级

  • 结果展示

vivo商城前端架构升级

  • 结果展示

vivo商城前端架构升级

【小结】

本篇文章介绍了 vivo 商城架构升级的背景,并从系统级、应用级、模块级、代码级四个层次,总结了 vivo 商城前端架构升级过程中的种种实践和探索,希望能给有类似需求的团队带来帮助。

我们在前端技术方面的探索并未结束,作为前端架构升级的第一篇,后面会围绕架构升级带来一系列的文章,为大家更详细的讲解其中的难点和经验,敬请期待。

更多内容敬请关注vivo 互联网技术微信公众号

vivo商城前端架构升级

注:转载文章请先与微信号:Labs2020联系

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这