• vivo 商城前端架构升级-总览篇


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

    【背景】

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

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

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

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

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

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

    【分层架构】

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

    技术演进过程:

    分层架构实施图:

    一、系统级

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

    1、前后端分离

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

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

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

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

    2、多端统一

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

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

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

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

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

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

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

    3、BFF

    • 业务现状

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

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

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

    • 关键技术

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

    • 直连Dubbo:

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

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

    • 集成GraphQL网关:

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

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

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

    (3)强大的API调试工具

    4、SSR

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

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

    主要优势在于:

    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客联盟等应用中广泛使用,极大的提高了开发效率。如下图:

    三、模块级

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

    1、极致模块化

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

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

    ➜  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**,对我们的提交进行强制校验。比如:

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

    • 修改类型

    style: 样式修改

    fix: bug修复

    feat: 功能开发

    refactor: 代码重构

    test: 测试类修改

    doc: 文档更新

    conf: 配置修改

    merge: 代码合并

    • 影响模块

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

    • 跟踪单号

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

    • 问题描述

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

    2、质量

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

    (1)代码检视:

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

    添加评论

    (2)代码覆盖率:

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

    • 服务端架构

    • 前台架构

    • 自动集成 GitLab

    • 结果展示

    • 结果展示

    【小结】

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

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

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

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

  • 相关阅读:
    洛谷—— P3353 在你窗外闪耀的星星
    洛谷—— P1238 走迷宫
    洛谷—— P1262 间谍网络
    9.8——模拟赛
    洛谷—— P1189 SEARCH
    算法
    May 22nd 2017 Week 21st Monday
    May 21st 2017 Week 21st Sunday
    May 20th 2017 Week 20th Saturday
    May 19th 2017 Week 20th Friday
  • 原文地址:https://www.cnblogs.com/vivotech/p/13625663.html
Copyright © 2020-2023  润新知