博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
记一次 Vue 项目的重构
阅读量:6813 次
发布时间:2019-06-26

本文共 4548 字,大约阅读时间需要 15 分钟。

上周没有更新原创技术文章,原因是忙着重构一个新接手的项目,此项目因为项目技术负责人离职,虽然投入人力持续增多,前端达到4人,后端3人,但因为新参与的童鞋对代码结构和业务的理解,导致项目开发了一个多月,还有一堆问题,达不到上线要求。接手项目之后,一开始对项目业务场景和代码进行简单的了梳理,跟了一天项目,观察提测后FE+RD的状态,自己也动手改了一天代码,不管是FE+RD包括自己都觉得实在是太难受了,小坑大坑不断,于是决定重构。重构不是个人冲动,而是的的确确存在各种大大小小的问题:

  1. 接口太碎:项目本身按照Vue组件化开发,但是页面每个组件独自采用vuex+ajax请求管理自己的数据,比如:首页由轮播图、各种列表和用户信息展现组成,导致首页从上到下7~8个模块,每个模块都各自发自己的请求,访问首页需要同时发出8个ajax请求

  2. 因为「1」提到的,单个组件数据都是使用Vuex进行管理,导致Vuex的store太乱:而且FE按照组件去开发,各自跟后端RD兑接口、联调,但是没有人来统筹安排,导致大量重复工作;除此之外,action和mutation中的业务逻辑代码太多,而不同页面需要不同的数据格式,则导致:

    1. 或者在mutation当中对数据进行重新整理

    2. 或者新开个接口,这样就造成接口越来越多,mutation部分代码越来越重。

  3. 一开始设计或者沟通有误。比如:用户信息相关的接口,需要传入用户id(uid),而不是通过登录cookie从passport获取;第三方接口需要用户信息,竟然请求的时候将cookie发给对方(幸好cookie是http only的,没有调通被我及时发现)

  4. 重复代码太多,抽象能力太差。一份代码在多个地方复制,导致代码改来改去最后都不知道哪里改了哪里没改

  5. 命名太乱,包括url、方法名之类,还有错别字,getAdcontent(用户地址信息),getmaildetail(用户地址信息)

  6. 研发人员缺乏全局意识,只管自己的代码,而不关心整个流程。由于前后投入人较多,没人对整个项目有把控,只能面向自己的需求编程。比如:积分获取页面,获取成功之后,联调成功,但是实际在积分获取列表页面却没有相关的记录信息;在比如:任何用户都可以领走别人的奖品,原因后端没做奖品是否是当前登录用户获取的校验

  7. 问题定位能力不够,遇见问题一调就是半天,找不到根本问题

介绍下项目背景:

此项目是一个用户积分任务和消费项目,一些页面需要用户登录,页面主要包括:首页、任务+列表、商品+列表、个人信息和记录以及其他类(说明和规则等)

项目用Vue+yog2编写,ajax请求部分使用vue resource

架构改造

整个项目还是用Vue+yog2来写,针对进入页面分为两种情况:

  1. 第一次通过网站URL进入某个页面,我称为:「首次后端渲染

  2. 非首次已经进入页面URL后,用户点击链接在项目内跳页,我称之为:「非首次跳转

整个流程整理如下:两个流程从「两个小人」开始看起

后端node Server代码部分

代码流程如下:

 
  1. router → middleware → page/api action → model → ral请求数据复制代码

其中在action部分,专门写了个 baseAction函数,封装了重复的代码,使用时传入用于获取数据的model方法和处理数据的方法即可。

render部分,针对页面第一次请求需要将页面数据放在HTML片段中chunk输出,而不是通过ajax请求(为什么不用vue ssr,可以看下历史公众号文章《》,之后单页内跳转是ajax请求)。详细代码如下:

client.tpl 部分代码:

baseAction 部分实现chunked

Client Vue部分代码

client主要流程是:

 
  1. vue router → created时期 判断是否有页面数据 →复制代码

  2. 提交mutation(有数据),dispatch action(异步拉取数据)→ state触发修改,页面dom生成复制代码

这部分流程图主要展现是Vuex和Vue resource部分的代码,通过Vuex的dispatch action,触发Vue resource的异步请求,等返回数据则commit mutation。

后端渲染+SPA单页应用

经过改造后整个流程变成:

  1. 「首次后端渲染」:此时需要后端渲染主要HTML+页面数据,利用chunked,先将不依赖后端数据部分返给浏览器,页面数据和后面的HTML拿到数据后再返给浏览器。 client.tpl被「一分为二」:HTML[0] + HTML[1]

    1. 将页面通用的css和js lib库,放在HTML[0]中,首先返回,浏览器先解析下载

    2. 业务代码初始化代码放在HTML[1], 等到获取到后台API数据一起返回

  2. 「非首次跳转」:这是一个单页应用的流程,用户点击链接,实际走的是vue的router,然后出发vue页面渲染,URL是通过history pushState mode更改实际URL,这时候如果强刷或者复制url在浏览器打开,又走「首次后端渲染」

    1. vue页面渲染需要的数据是通过vue-resource发起ajax请求,拿到数据之后commit mutation改变state

Vuex梳理

之前代码每个组件都单独ajax请求自己的数据,导致Vuex的module特别多特别乱,而且后端api接口太多太碎,不好维护。最后开发的童鞋自己都在群里抱怨,找个action或者mutation都不知道在哪个文件内,需要搜代码。。

首先做约定,明确什么时候使用Vuex:

页面view相关的数据才使用Vuex来管理,页面功能性ajax(例如签到、兑换)不要使用vuex;「首次后端渲染」和「非首次跳转」的view数据都通过commit mutation来修改state,最终映射到DOM表现上;功能性ajax则在组件内自己发请求实现,保持组件内聚;

P.S:这就是「贫血组件」和「充血组件」的区别,本身组件内的状态和逻辑都放在全局store管理,会增加store复杂度,降低效率(代码性能和开发效率)

然后,收敛vuex module

收敛是根据业务页面做的,前文提到:

页面主要包括:首页、任务+列表、商品+列表、个人信息和记录以及其他类(说明和规则等)

其中需要数据的有:首页、任务(详情、列表)、商品(详情、列表)和个人中心四个。

改造前module:

改造后module针对业务梳理的四个大页面内容,保留了四个:

减少mutation数据处理逻辑

复用后端接口数据格式,减少mutation数据处理逻辑

改造前很多action存在下面的代码(注意箭头部分):

其中这个循环主要做两件事情:修改 type、修改 img_urlurl,实际根本没有必要:

  • 修改 type:实际这已经是页面view层的逻辑了,在vue的模板或者computed中做更合适

  • 修改 img_urlurl:这里实际是产品的封面图,改成 url反而更不合适了,而且导致了数据不一致

代码可以直接用 item即可!即不需要做额外的循环处理,保证数据一致性,避免前端的二次设计

API显性声明

之前所有的api都是走了一个 proxy,通过node转发一下,直接到了后台API接口,代码如下:

看似很方便甚至有点暗爽的实现,实则带来了下面的问题:

  1. 接口非显性声明,降低可控性,造成没法枚举有多少接口,各个接口需要什么参数,增加维护成本

  2. 安全性!后台这个服务是完全暴漏给了前端,如果存在敏感的接口,前端js就可以直接透传利用

改造后的代码放在model层,供「首次后端渲染」和「非首次单页」ajax请求使用:

优化

除了做代码重构改造外,还在间隙中做了一些优化,这里记录一下:

后端渲染使用chunked

详见本文「后端node server部分代码」和「后端渲染+SPA」

数据复用

很多页面设计会在首页和列表页面存在有产品的title、图片和简单的一些meta,例如下图:

点击链接进去详情页面可以直接利用,这部分数据我们做了复用。

实现方法是:页面点击的时候,将该条数据内容commit给下一个页面的mutation。

缓存

缓存在node和前端Ajax API多有,后端node主要缓存的是首页,因为首页需要请求4个接口(接口梳理后),其中三个接口是跟用户登录态无关的,这三个接口可以用lru-cache缓存起来。

前端的ajax api缓存是在 get请求增加的,可以根据实际情况用,根据url作为key,使用sessionStorage存储(同时cache类自己实现了缓存时间)

技巧

除了优化外,我在介绍下两个技巧:单页切换view的loading和统一的错误处理。

在单页跳转内,下一个view需要API请求获取数据,然后才能渲染,这时候需要加载个loading显示(或者做个切换动效)。

原理是:

  1. 利用eventBus,在router中添加两个事件 closeLoadingvue.action.error,分别用于「关闭loading」和「展现页面数据错误的错误页」

  2. loading展现在router的 beforeEach的钩子内实现,loading的事件在vuex的action获取数据成功之后发送

  3. 错误的触发有vuex 的 action / mutation 来发送事件

eventBus也不用自己写,可以直接用Vue实例的 $on$emit$once等就够了,代码如下:

 
  1. import Vue from 'vue'复制代码

  2. export default new Vue()复制代码

总结

重构主要做的事情是:

  1. 统一接口请求,重新梳理API;

  2. 收敛Vuex store设计(包括mutation/action的聚合,state简化);明确Vuex的使用边界

  3. 明确组件职责边界,划分「充血组件」与「贫血组件」

  4. 抽象封装重复的代码逻辑

  5. 做了一些简单优化

说下成果:项目已经delay很久,从4月初到5月初已经一个月了还没上线,接手项目是五一前,整个重构共2个人力用了三天完成95%的工作,目前已经提测,

下面是重构项目的团队内部问题总结:

  1. 项目开发中一定要有大局意识,虽然现在项目多是分组件来的开发方式,但是开发前要跟大家交代清楚约定、规范,什么该做什么不该做;

  2. 技术负责人多 check 代码,防止错误的道路上越行越远;

  3. 要有全局意识,关注整个流程,不要只看到自己的「一亩三分地」,比如:在某个商品页面,购买/兑换成功了,不要认为没有问题了,可能记录页面还没有展现(后台接口没有入库);

  4. Don’t repeat yourself!看见重复代码就浑身难受,「抽象」能力是工程师的基本能力。

  5. 增强debug能力,发现问题直觉就能判断出来哪个环境,然后针对性debug

@三水清
未经允许,请勿转载。掘金更新比公众号晚一周左右。
感觉有用,欢迎关注我的公众号,最新文章第一时间看到!
你可能感兴趣的文章
武器加持无人机,远程操控就可以抓获犯罪团伙
查看>>
MySQL数据库迁移
查看>>
IOS应用提交所需的ICON
查看>>
第90届中国电子展聚焦行业新热点,拉动产业链上下游快速发展
查看>>
量子力学多世界解释:这个世界的你是穷光蛋 另一个世界是亿万富翁(文中有赠书活动)...
查看>>
不要小看了互联网智能锁,它正撬动整个多元化居住产品时代!
查看>>
工人小明的新同事
查看>>
OPC UA的安全性分析以及正确使用指南
查看>>
使用树莓派和 projectx/os 托管你自己的电子邮件
查看>>
关于nmonanalyser报错“输入超出文件尾”的解决方法
查看>>
Ubuntu 16.04安装idea
查看>>
Navicat标识为灰
查看>>
轻松面试找到理想员工-非官方的面试技术指南
查看>>
oracle 删除用户下对象 脚本生成
查看>>
当主库发生宕机,从库如何接管主库
查看>>
卷影副本(Shadow Copies)
查看>>
重新回归
查看>>
AngularJs 知识
查看>>
Spring.NET的AOP怎么玩
查看>>
64位Ubuntu下安装IE6步骤
查看>>