上周没有更新原创技术文章,原因是忙着重构一个新接手的项目,此项目因为项目技术负责人离职,虽然投入人力持续增多,前端达到4人,后端3人,但因为新参与的童鞋对代码结构和业务的理解,导致项目开发了一个多月,还有一堆问题,达不到上线要求,接手项目之后,对项目业务场景和代码进行简单的了梳理,决定重构。重构不是个人冲动,而是的的确确存在各种大大小小的问题:
介绍下项目背景:
此项目是一个积分项目,一些页面需要用户登录,页面主要包括:首页、任务+列表、商品+列表、个人信息和记录以及其他类(说明和规则等)
项目用Vue+yog2编写,ajax请求部分使用vue resource
整个项目还是用Vue+yog2来写,针对进入页面分为两种情况:
整个流程整理如下:

代码流程如下:
router → middleware → page/api action → model → ral请求数据
其中在action部分,专门写了个baseAction
函数,封装了重复的代码,使用时传入用于获取数据的model方法和处理数据的方法即可。
render部分,针对页面第一次请求需要将数据放在HTML片段中返回的优化(为什么不用vue ssr,可以看下历史公众号文章《Vue SSR 从入门到Case Study》)。详细代码如下:
client.tpl 部分代码:

baseAction 部分实现chunked

client主要流程是:
vue router → created时期 判断是否有页面数据 → 提交mutation(有数据),dispatch action(异步拉取数据)→ state触发修改,页面dom生成
这部分流程图主要展现是vuex和vue resource部分的代码,通过dispatch action,触发vue resource的异步请求,等返回数据则commit mutation。
经过改造后整个流程变成:
client.tpl
被「一分为二」:HTML[0] + HTML[1]之前代码每个组件都单独ajax请求自己的数据,导致vuex的module特别多特别乱,而且后端api接口太多太碎,不好维护。最后开发的童鞋自己都在群里抱怨,找个action或者mutation都不知道在哪个文件内,需要搜代码。。
页面view相关的数据才使用vuex来管理,页面ajax(例如加载更多)不要使用vuex
收敛是根据业务页面做的,前文提到:
页面主要包括:首页、任务+列表、商品+列表、个人信息和记录以及其他类(说明和规则等)
其中需要数据的有:首页、任务(详情、列表)、商品(详情、列表)和个人中心四个。
改造前module:

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

复用后端接口数据格式,减少mutation数据处理逻辑
改造前很多mutation存在下面的代码(注意箭头部分):

其中这个循环主要做两件事情:修改type
、修改img_url
为url
,实际根本没有必要:
type
:实际这已经是页面view的逻辑了,在vue的模板用个容易判断更合适img_url
为url
:这里实际是产品的封面图,改成url
反而更不合适了代码可以直接用item
即可!
之前所有的api都是走了一个proxy
,通过node转发一下,直接到了后台API接口,代码如下:

看似很方便甚至有点暗爽的实现,实则带来了下面的问题:
改造后的代码放在model层,供「首次后端渲染」和「非首次单页」ajax请求使用:

除了做代码重构改造外,还在间隙中做了一些优化,这里记录一下:
详见本文「后端node server部分代码」和「后端渲染+SPA」
很多页面设计会在首页和列表页面存在有产品的title、图片和简单的一些meta,例如下图:

点击链接进去详情页面可以直接利用,这部分数据我们做了复用。
实现方法是:页面点击的时候,将该条数据内容commit给下一个页面的mutation。
缓存在node和前端Ajax API多有,后端node主要缓存的是首页,因为首页需要请求4个接口(接口梳理后),其中三个接口是跟用户登录态无关的,这三个接口可以用lru-cache缓存起来。
前端的ajax api缓存是在get
请求增加的,可以根据实际情况用,根据url作为key,使用sessionStorage存储(同时cache类自己实现了缓存时间)

除了优化外,我在介绍下两个技巧:单页切换view的loading和统一的错误处理。
在单页跳转内,下一个view需要ajax获取数据,然后才能渲染,这时候需要加载个loading显示(或者做个切换动效)。
原理是:
- 利用eventBus,在router中添加两个事件
closeLoading
和vue.action.error
,分别用于「关闭loading」和「展现页面数据错误的错误页」- loading展现在router的
beforeEach
的钩子内实现,loading的事件在vuex的action获取数据成功之后发送- 错误的触发有vuex 的 action / mutation 来发送事件

eventBus也不用自己写,可以直接用Vue实例的$on
、$emit
、$once
等就够了,代码如下:
import Vue from 'vue'
export default new Vue()