高效支持运营活动需求-模板化

原创声明

一、相关背景简介

我司作为一个快速发展中的公司,在运行过程中,面临着大量的运营活动类需求。这类需求的特点可以总结为:

1. 需求频率较高

2. 项目开发时间短

3. 线上生命周期短

4. 部分活动还具有持续性,比如特定的时间会上线一次

基于这些特点,每次耗费同样多的人力和时间去支持此类项目,在前期开发中给了我们很大的压力。为了更高效、低成本地处理这类需求,释放部分人力,我们也沉淀出了自己的开发方式,如下图所示:

1. 项目脚手架

随着前端开发越来越复杂,项目的前期搭建成本也变得越来越高,一个合适的种子项目,可以让我们在开发的时候只关注核心业务,无需被繁琐的配置干扰。脚手架不仅能帮助我们快速开发,也能在保证团队统一开发的情况下降低维护成本。

2. 固定功能模板

针对一些功能相对固定的活动,比如包月,充值,囤书节等,我们专门进行了模板开发。通过在运营平台配置样式,来保证同一个活动在每期都能有不一样的风格呈现;通过活动id的区分,来关联活动的后台数据。这些模板带来了很多人力的释放,让开发成本直接降到了0,至此我们也尝到了模板化开发带来的好处。

3. 通用型模板

当然,我们并不能针对每一类活动都做一个模板,那我们如何开发一个较为通用的模板,来承接大部分的运营活动需求呢?这个是我们目前正在考虑的问题,也是这篇文章要引出的思考。

本文以一个已经开发完成并投入使用的项目为例,来做一个关于模版化项目的总结,希望可以从中思考如何做好模版化项目以及通用型模版的实现方案。

二、项目背景简介

作为内容为王的文学公司,对新书的运营推广必定是一个重要且高频的需求类型,所以我们固化了此类需求,开发了相对应的模板。

由于新书运营模板的实现方式不同于以往固定功能模板的开发,其推动过程中积累的经验和它的技术方案对于通用型模板的开发存在参考价值,所以本文对已经上线的新书运营模板进行了总结,并希望从中思考关于通用型模板的解决方案。

三、项目难点分析

新书模板既要支持丰富的功能,又要保证页面设计的灵活,这会带来一定的技术挑战。一期我们优先开发部分常用的功能组件,其中涉及到:

1. 23个模块

2. 160多个可配置参数

3. 模块之间的逻辑关系的处理

4. 页面渲染方案 (组件可自由选择、组合)

如何对这些模块进行高效开发,如何处理模块之间存在的各种逻辑关系,如何实现从运营平台的配置到页面渲染的过程,项目进入开发阶段之前,必须先对这些问题有明确的思路,在文章的第五部分会详细介绍解决方案。

四、前端如何发挥主动性

在说具体的技术方案之前,我想从项目的角度来分析下,作为一名前端技术同学,在项目开发的整个过程中,跳出自身的技术环节,能否发挥自身的驱动力,影响到其他环节的进行?我们透过新书模板这个项目来具体看一看。

1. 推动模块类别划分

拿到产品给出的一堆模块,我们可能会存在一些疑问,比如这么多模块,先做哪个后做哪个,有没有一些重复或者不合理的地方,当产品和交互对这个问题没有明确答案或者答案并不是很合理的时候,前端同学可以结合实际需求和技术实现,对这些模块进行拆分、合并等调整处理,在项目初期保证模块的合理性,避免开发中再去做这类调整,影响进度。

新书模版一期开发,我们最终整理出23个模块,这么多模块如何推动,一个合理的开发顺序是非常必要的,所以我们根据模块的特点,进一步划分,将其分为三大类,按照类别确定开发和测试的优先级,整个事情就变得简洁明了了。

最终的模块划分图:

2. 推动视觉规范落地

视觉规范就是模版的设计规范,包括固定的样式规范和可配置样式参数规范,有了视觉规范,才能保证不同的设计同学,在后期进行基于模版的项目设计中,按照一定的规则进行。

为保证设计同学的发挥空间,提高页面视觉的可拓展性,呈现丰富多变的页面风格,前端同学从技术实现的角度协助评估视觉规范的可行性,并提供更多的可能性及建议,比如:

1. 通用样式和默认样式设置

2. 选填or必填

3. 参数类别,文字or图片

4. 样式细节规范,比如标题宽度可定义100%,保证可以在通栏的空间内进行设计;按钮图片定高不定宽,比较灵活;本地视频模块需要配置视频封面,腾讯视频资源不需要

最终设计同学会输出一个视觉规范,类似下图:

设计同学 / 前端开发 / 测试同学 / 运营小伙伴都需要参照设计规范标准。

3. 推动交互文档输出

交互文档是开发和测试的依据。因为项目涉及模块较多,模块与模块之间可能存在着逻辑关系。交互以什么形式输出更友好,如何完善交互细节,提升用户体验…,需要交互同学和各环节进行沟通协作,前端更应该积极参与到交互输出到阶段,从专业的角度来提供更好的建议。

4. 约定后台api,前后端并行开发

项目涉及到的 api 参数较多,为提高前后端开发的效率,前端可以优先与后端同学确定接口数据结构及模块的参数字段,这样就可以使用本地数据模拟接口,不仅不必依赖 api 给出的时间,还有利于各种状态的切换测试。前后端都按照约定好的 api 数据进行开发,后期切换到线上接口,出现问题的概率也比较小。前端开发的过程,也是对api查缺补漏的过程,如果发现不合理或者缺漏的地方,也可以及时同步给后端同学。

5. 分阶段进入测试

这么多模块测试同学怎么测更合理,效率会更高?是不是需要等到全部开发完毕了再进行测试?当然不是。项目按照模块类别进行开发,比如页面展示类的开发完毕之后,就可以进入测试阶段了,先测试每个独立的模块,再测试模块之间的逻辑关系,做好任务阶段性拆分,让事情有条不紊的进行。

四、前端技术方案

我们的目的:运营小伙伴通过在平台选择组件,配置组件的数据,自由组合组件,独立完成活动页面的搭建。

项目的整体开发思路,只画了从配置到渲染的主要流程部分:

运营平台选择组件,配置数据(包括活动基本属性的配置,模块配置,模块扩展数据的配置等)发布页面-》后台 server 根据配置信息,返回 JSON 数据-》前端根据 api 返回的 JSON 数据,完成页面渲染。

本文主要针对前端技术方案展开讨论:在前端组件化开发的大潮下,结合项目的特点,我们以组件为维度来进行项目开发,技术栈选择 Webpack+Vue.js。

下面我们具体分析:

1. 单文件组件处理模块

组件 (Component)是 Vue.js 最强大的功能之一。它可以扩展 HTML 元素,封装可重用的代码。但是基于 HTML 的模板组件也带来了一些问题:要么 HTML 标记使用丑陋的 JavaScript 字符串,要么将模板内容和组件定义写在不同的文件中,css在组件化中也被遗漏。为了解决这些问题,Vue.js 提供了一种叫做Single File Components (SFCs) 的单文件组件的方案,自定义了一种 .vue 文件,可以把html, css, js 写到一个文件中,从而实现了对一个组件的封装, 一个 .vue 文件就是一个单独的组件。

前端组件化的核心思路就是把一个复杂的东西拆分成颗粒度合理的小东西,针对新书模板项目而言,我们把页面拆分成一个个的组件,组件和组件相互组合,就成了一个应用。下面是一个组件的代码示例:

author.vue

组件带来的好处很明显,一个模块的 CSS/JS 和模板放在一起,CSS/JS 与页面其他模块的静态资源是相互独立的,单个模块也能够完整的跑起来,更加利于模块的复用,做到模块解耦。

SFCs 使得我们对于多模块的开发变得非常方便,这主要得益于 Vue-loader,这个加载器使得 SFCs 成为可能 。只要你把构建工具设置的很舒服,单文件组件就是模板选项中的王者。具体到新书模版项目,单文件组件带来的好处:

1. 23个模块,就对应23个 .vue 文件,模块之间相对来说是非常独立和完整的

2. 单个模块只需要维护对应的 .vue 就可以了,代码结构清晰,维护成本低

3. 可读性更强,方便复用

当模块变的越来越多的时候,如何更方便的查找和维护模块就变得更加重要,目前我们采用的方案是单独抽出一个 js 文件来做模块的映射和引入:

2. 动态组件实现页面渲染

Vue.js 提供了动态组件,通过使用保留的元素,动态地绑定它的 is 特性,让多个组件可以使用同一个挂载点,并动态切换。简单来说,就是几个组件放在一个挂载点下,然后根据父组件的某个变量来决定显示哪个。

我们来思考下,为什么要在新书模板项目中使用动态组件以及如何使用?

运营平台的配置数据,服务器会返回给客户端,我们约定的数据格式大概是这样的:

modules 数组里以对象的形式存储已选择的组件的配置数据。其余公用的字段,放到 modules 外。每个组件对象有自己的 mid,用来区分组件,因为一个页面中同一个组件可以使用多次,所以组件还有唯一的身份 id。

那么前端接收到 JSON 数据,怎么进行页面的渲染呢?

1. 方案一

直接对数据 modules 进行循环,通过判断 modules 数组里每个对象的 mid 对当前组件进行处理,代码如下:

这种方案的缺点很明显:

从代码的书写标准上来看,不够简洁美观,重复代码多,所有的模块标签都要写;

从逻辑的合理性来看,每次循环到符合条件的模块并没有跳出当前循环,还会继续直到所有的模块都循环完毕,会耗费更多渲染时间。

2. 方案二

我们可以换个思路,巧妙的利用动态组件来渲染数据,把接口数据 modules 里每个组件的名称 item.mid 和 vuelist.js 里组件的名称对应起来,通过对 modules 数组进行循环,同时把数据传入对应的组件里,达到只渲染配置组件的目的。

父组件里的 template 代码

vuelist.js

这种方案的优点也很明显:代码非常的简洁,不会造成重复的循环;单独维护组件列表 vuelist.js 就可以了,可读性很强,新增或者删减模块并不需要更改 template 代码。

3. event bus 解决组件之间的通信

Vue.js 提供了组件通信的方法,比如父子组件之间可以使用 props,自定义事件等方式进行通信,兄弟组件之间可以间接的通过共同的父组件进行通信,复杂的场景还可以使用 Vuex。

在新书模板项目中,组件是平行但并不独立的,组件与组件之间存在着逻辑关系,比如组合关系,因果关系。因为我们并不确定页面最终选择了哪些组件,所以使用 Vuex 并不是很好的选择,因为 state 的值会存在一些问题。如果我们通过父组件间接的进行通信,一两个组件还可以,对于组件很多的项目非常的不适合,大量的上传派发,会让耦合性大大的增加,可读性非常差,最后搞不好自己都不记得写了什么。

综合考虑,event bus 还算一个比较合理的方案,那什么是 event bus,项目中如何使用 event bus 呢?

我们对发布订阅模式并不陌生,它也是js种常用的一种设计模式。EventBus是一个事件发布/订阅总线,它可以

1. 让组件之间的通信更加简单

2. 使事件的发送者和订阅者之间进行解耦

3. 代码更加简洁,可读性更强

在实现程序中相互无关联的部分之间的沟通方面这种模式是非常好的选择。

下面是使用使用 Vue.js 创建全局事件总线(Global Event Bus ) 示意图

确定了方案之后,我们需要解决一些问题,比如哪些组件需要通信?和哪个组件通信?event 字段如何定义?我们是这么约定的:

1. 有绑定关系的模块,接口会返回代表绑定关系的字段 rid

2. 字段 rid 的值就是与此模块有绑定关系的模块 id,是唯一的

3. 比如 a 和 b 是两个绑定模块,那么 a.rid === b.id,所以 event 字段就用 id/rid,根本不用关心事件名称

代码示例:

4. 异步组件实现按需加载

按需加载本质上是由于前端页面越来越复杂,代码体积越来越大,我们需要对页面资源的加载做细粒度的控制。在新书模版项目中,我们有23个组件,但是每个活动中配置使用的组件数量不固定,目前因为组件不是特别的多,所以在构建的时候23个组件的代码是被打包到一起的。随着新书模版的迭代,或者我们在做通用型模版的时候,组件会变得越来越多,这个时候,如果所有的组件还是被打包到一起的话,会加载很多并没有配置使用的组件,造成加载缓慢,资源浪费。所以,我们可以考虑使用按需加载。

在新书模板项目中,我们使用了 webpack+Vue 的技术方案,基于这种方案,如何实现按需加载呢?

1.使用 vue 注册一个异步组件

2. 使用 Webpack 的 “code splitting” 功能,把异步组件打包到单独的 js 文件中

项目代码片段:

只有当组件需要被渲染时(1. 接口数据里有这个模块;2. 用户交互的时候才去触发渲染),页面才会请求去服务器下载 rule.js,我们可以适当的根据组件的使用频率和在页面中的位置,去做一些异步加载的处理。因为如果每一个组件都独立打包的话,页面上的请求会变得太多,对页面性能会有影响。具体使用方式还要考虑项目场景。

上面三种分别是 webpack 不同版本的异步加载写法,有些语法支持自定义分包模块的名称,并有加载失败的回调处理,有些则不行。webpack1 和2、3在模块加载的机制上也不同,有兴趣的可以了解下 webpack 对 es6 模块的支持,tree-shaking 的原理以及静态编译,动态编译。

五、项目总结与思考

新书模版上线3个月,累计使用了20多次,对于人力的节省是毋庸置疑的。在使用的过程中我们也收集到一些问题反馈,还在不断的优化中。

通过对新书模版项目的总结,一方面是思考如何推动模版类项目的开发,比如前期结合需求、设计、运营平台使用、页面加载来确定配置参数的设置,还要为组件的开发和维护,页面资源的加载等选择更优方案。在项目推动的过程中,前端同学不要只局限于自身的技术实现环节,了解项目目标并积极与各环节互动,才能更好的支持项目,发挥更大的影响力。

另一方面,通过对技术方案的整理,思考通用型模版是否可以在此方案上通过增加模块进行扩展,会存在哪些问题,有没有更好的方案,以及项目本身目前还存在的漏洞,比如性能监控,异常监控,运营平台更友好的体验等。

如果大家有更好的想法或者方案,欢迎一起交流~

本文作者:赵冉

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180108G0JU5Z00?refer=cp_1026

扫码关注云+社区