十年•杭研技术秀 | 网易蜂巢的工业化前端架构(下)

社区编辑2018-05-15 16:42

本文接上文十年•杭研技术秀 | 网易蜂巢的工业化前端架构(上)


组件之间的关系

 

前面提到组件之间的关系有继承、扩展和嵌套,还有一种关系是包含,表示一个组件内部调用了另一个组件。这些关系都可以归属为依赖。

 

下面这张图展示了蜂巢的一部分组件和它们之间的依赖关系:

 

蜂巢组件(部分)依赖关系图

 

组件库

 

组件库是一系列组件的集合。

 

因为本土优势,蜂巢的组件化框架使用了我们公司的RegularJS(https://github.com/regularjs/regular);通用组件库使用了我写的Regular UI(https://regular-ui.github.io/index.html)。

 

根据交互和视觉规范,蜂巢产品下的五个单页系统的组件风格是统一的,因此它们之间有很多通用业务组件可以共享。为了减少维护成本,我们在Regular UI的基础上,加上蜂巢的视觉样式和一些新的通用业务组件(图3中绿色的组件),再封装成一套专为云计算使用的Cloud UI组件库。

 

最后,蜂巢的组件化架构如下:


蜂巢组件化架构

 

技术选型:RegularJS + Regular UI + Cloud UI

 

规范化

 

“现代工厂制度是工业革命发展的必然产物。”

 

模块化和组件化确定了开发模型,而这些东西的实现需要规范去落实。

 

在以前没有规范的日子里,我们的项目中一度出现过以下问题:

  • 各模块代码风格不一致。一个程序员接手另一个程序员的模块后要预热、理解甚至重构;
  •  各模块对外接口不一致。比如有的模块输出对象、有的模块输出构造器,导致使用起来很混乱;
  •  容易产生重复功能的模块和组件。比如有段时间蜂巢项目中同时存在4个相同功能的自定义Select组件的情形;
  •     …

 

这些问题的存在,已经降低了模块化和组件化的实用性。会大大影响开发效率,增加维护成本,进而会影响网页性能,产生隐藏的bug。

因此,我们也对团队的开发方式和开发流程进行了规范化改进。

 

目录结构

 

上文中提到,按照组件化思想,我们对项目的目录结构进行了重新的梳理。现在目录结构如下:

src/                # 源文件

    base/           # 基础类库

    common/         # 通用组件和通用业务组件

    specific/       # 业务组件

    module/         # 模块组件

    page/           # 页面及入口css和js

    service/        # 数据服务

    icons/          # 图标源文件

        png/        # 雪碧图标源文件

        svg/        # 字体图标源文件

    assets/         # 静态文件

dest/               # 生成文件

    css/

    js/

    img/

    fonts/          # 图标字体和专用字体

    vendor/         # 第三方库

node_modules/

    cloud-ui/       # Cloud UI组件库

package.json

.gitignore

.eslintrc           # eslint配置

 

源文件和目标文件完全分开,依赖统一用npm进行包管理。

 

common、specific和module三个目录存放组件:

  • common存放通用组件和通用业务组件(大部分移入了Cloud UI);
  • specific存放普通业务组件;
  • module存放业务模块组件。

 

编码规范

 

对项目中的各种语言,我们参考了Airbnb、Google等市面上比较通用的代码规范,再结合自己的代码特点,制定了相应的规范(https://regular-ui.github.io/start/rule.html):

  • 命名规范
  •  CSS/MCSS编码规范
  •  JaveScript编码规范
  • Regular组件设计规范

 

Lint

 

以前的编码规范仅是口头约束+书面文档+CodeReview,约束力不强。今年引入了ESLint进行强制性约束。

我们的配置策略如下:

1.    花一天时间先遍历ESLint的437条规则;

2.    筛选需要的规则,并在组内讨论;

3.    先将确定的规则全部配error,然后再根据情况降级(因为往往配了warning,大家就不太care了);

4.    lint存在error时禁止提交代码。

 

虽然初期配置ESLint的时间成本较高,但从长远看,ESLint能大大提高代码质量,提升协作效率。所以之后打算给CSS也配上Lint。

技术选型:ESLint

 

自动化

 

“现代工业其所以区别于工场手工业,是由于机器起了主要的作用。”

 

自动化是“手工工场”和“工业革命”的分水岭。(仅作比喻,与历史无关)

 

图标合并

 

以前在蜂巢项目中,雪碧图是用PS手动拼的,字体图标是用icomoon手动生成的,然后再将导出的文件手动拷到项目中的。这是典型的手工工场生产方式。

 

这种方式存在以下问题:

  •  PS和icomoon谁管理比较好,前端还是视觉?
  • 想知道图标对应哪个className,每次都要在源码中找一遍;
  • 多人同时编辑二进制文件,会产生git冲突;
  • 产品迭代迅速,遗留许多旧图标不敢删除。

 

如今在项目中引入了SpriteSmith和FontCustom两个Gulp插件,让图标能够自动合并,解决了以上所有问题,步入了工业化生产。

视觉只需提供svg和png图标源文件,前端按照想要的className命名,放入icons目录中即可使用。其实这也相当于是图片资源的模块化。

技术选型:SpriteSmith + FontCustom

 

可视化组件文档

 

前端开发和后端开发不同的是,前端开发是可视化的。

 

后端文档只要写个markdown文件,放在git仓库就能阅读;而在前端文档中,你写个m-modal-lg,别的开发者根本不知道你这个模态框多大,是个什么样子,去翻源码也无法感知组件的具体使用场景。

 

因此在前端工程中书写可视化的组件文档,也是很有必要的。

 

但这种高科技文档必然要插入CSS和JS,如果手工写肯定工作量很大,一是在迅速的产品迭代中来不及,二是会降低大家写文档的积极性。

 

对此,我们做了两项工作:

1.    写了一个PostMark插件,在markdown的基础上,将代码块中的Regular组件示例代码同步转换成JavaScript代码,使组件能够在最终的文档中活灵活现;

2.    将组件JS文件中JSDoc风格的注释提取出来,转换成文档的API部分,插入到文档最后。

 

剩下的书写工作就很简单:前端工程师只要在每个组件的demo文件夹中创建md文件,并书写文档内容和组件示例,在组件JS文件中书写API,就能自动生成相应文档。生成效果类似Regular UI文档(https://regular-ui.github.io/jsunit/dropdown.html)。

技术选型:PostMark + JSDoc

 

前端自动化测试

 

前端自动化测试能够保证代码质量、减少人肉测试、提高团队开发水平,这些优点是不言而喻的。

但它配置比较复杂,UI测试成本很高,很多团队对其望而却步。

 

由于产品迭代迅速,我们遵循维护自动化测试成本最低原则,在项目中只覆盖:

  • 基础类库的单元测试;
  • 通用组件和通用业务组件的单元测试;
  • 通用组件和通用业务组件简单的UI测试。

 

由于RegularJS的MVVM特性,大部分组件的UI测试可以省略,因此这部分工作主要以给Regular UI和Cloud UI两个组件库加单元测试为主。

市面上前端测试框架有很多,选择哪个都不会有太大问题,最重要的是你要开始做,QA一定很开心。

技术选型:Karma + Mocha + Expect.js

 

构建工具

 

以上几点都是单项工作的自动化,要让它们相互衔接,实现整套工作的自动化,还需要一套完整的构建体系。

目前Gulp是处理工作流的最佳选择。

技术选型:Gulp

 

由于蜂巢产品下有多个系统,如果每个系统都搭一套gulp+webpack+babel+…,就不能保证几个平台的统一性,而且维护起来成本较高,是得不偿失的。因此实现一套独立于项目的构建工具是最好的解决方案。

 

我把本文中描述的这种工业化前端架构称为Pursuit架构(https://github.com/rainfore/pursuit),PURSUIT是多个技术栈单词的合并:webPack + gUlp + Regular + mcsS + rgUI + eslinT,中文意思是追求,意味着不断追求前端技术、紧跟时代发展潮流。

 

然后按照这套架构实现了对应的构建工具pursuit-cli(https://github.com/rainfore/pursuit-cli),目前已在蜂巢产品下的各个系统中使用。

 

最后,整套Pursuit架构的工作流程如下:


工作流程图

 

  • 使用gulp作为基本工作流;
  • 使用webpack+babel编译打包,再用uglify压缩js;
  • 使用mcss预处理css,再用minify压缩css;
  • 使用spritesmith生成雪碧图,再用imagemin压缩png;
  • 使用fontcustom生成字体图标;
  •  使用eslint规范编码格式,并自动fix;
  •  使用karma+mocha进行自动化测试,并输出测试报告;
  •  使用postmark+jsdoc生成可视化组件文档。

 

其他

 

至于性能优化、项目部署、数据统计等其他前端架构问题,解决完本文中提到的四大方面问题之后可以很好处理。且与前工业化架构的解决方法相同,这次蜂巢架构没有做相关调整,因此本文不再介绍。

 

——赵雨森

网易杭州研究院云计算平台产品部前端组