前端资源治理(一):问题及思路

2,158 阅读13分钟

作者:李刚松

0.也谈前端工程化

随着前端技术的飞速发展,前端需要一种更加工程化的方式解决前端开发日益复杂的问题。前端工程化本质也是软件工程的一种,由于软件工程并无严格的定义(或者说缺乏统一的定义),因此前端工程化的内涵其实相当宽泛,一般来说,前端工程化重点关注的是研发和维护效率,所有最终目的是这个的,都可以算作前端工程化的范畴。 前端工程化近几年也是技术热点,基本上大型前端技术交流会议都有此专题,从规范、组件、编译及构建、工作流、持续集成、监控等多个维度都有涉及,笔者尝试从前端资源治理的角度谈一下前端工程化,本文是系列文章的第一篇,主要讲问题及解决的思路,不涉及具体的实现细节。

1.前端资源治理的含义

首先,这里所说的前端资源,并非是仅指js、css、图片等静态资源,页面、后端接口、配置数据、监控点等,都可以纳入前端资源的定义的范畴。

在工作中,你是否会碰到以下问题:

  1. 同事或者领导发现某个页面有bug,需要在微信群或者内部沟通工具大群里问是谁负责?可能还要挨个艾特各个TL,需要各个TL确认。
  2. 某个组件要升级,但是不知道那些页面使用了,需要在沟通群里问或者搜项目源代码,逐个找到负责人。
  3. 某个大型营销活动突然要换一个新的氛围logo,但是不知道哪些页面使用了旧logo,需要安排巡检,人肉去找出来。
  4. 告警发现某个重要页面的出现了内容空窗,原因是运营同学没有及时补充运营数据,但是不知道是哪个运营负责,需要在微信大群或者内部沟通工具大群里问。
  5. 大促来临,某个重要页面的流量预计有10倍或者20倍的增长,要通知各个接口的同学做扩容和容灾准备,需要手工梳理页面的依赖的接口列表。
  6. 某个限时的页面已经到点下线,但是仍然有流量,不知道流量入口在哪里。
  7. 我要在统计系统上查看某个页面的性能数据,但是该系统是以页面名字而不是地址来查找的,查找过程找的人老眼昏花。
  8. 某个后端接口要升级或者要下线,需要分析nginx的访问日志找到页面地址,然后再拉各个TL,逐个确认都是哪些同事负责。
  9. 等等等

上面的问题一般是大型复杂业务场景(通常是多个团队合作开发,业务复杂,页面成百上千甚至上万)下才有的,如果你所在的团队也有上面的问题,那么我认为你也需要对前端的资源进行治理。

那么什么是前端资源治理呢?笔者对其的定义是:

将前端相关的页面、js/css/图片/字体、接口、配置、监控点等的依赖关系进行收集、存储和管理,并将割裂的组件系统、配置系统、监控系统、业务系统等进行重构和整合,最终形成以页面管理为基础的统一的有序的平台,所有关联信息都能够被查询和检索,最终实现整体协作效率的提升。

此处使用“治理”而不是“管理”的原因,“治理”一词更强调合作整改的过程。在很多互联网企业,通常已经有一些独立的组件系统、配置系统、监控系统等,但是这些系统很多都是独立的碎片化的系统,彼此都是割裂的,割裂意味着缺乏协同,进而影响研发效率。因此,前端资源治理的一个关键词是“整合”,整合已有的系统。

第二个关键词是“关联关系管理”,前端相关的页面、组件、js/css/图片/字体、接口、配置、监控点及负责人等,他们是存在关联关系的,比如页面是谁负责的、谁修改的、引用了哪些组件、图片、字体、接口、在什么地方配置数据、监控点都有哪些等,我们需要把这些关联关系在管理端记录下来,并提供检索和查询。

2.前端资源治理的实现

前端资源信息看似繁杂,js、css、图片、页面、后端接口、配置数据、监控点等,但是他们有一个串联的锚点,这个锚点就是页面,不管是H5、小程序,还是原生APP,不管是从研发的角度,还是从反馈问题的角度,基本上都是以页面为单位进行的,其他的如组件、CSS、图片、接口、配置等,都是被页面引用的,都可以通过页面串联起来的,下图可以清晰的表达出这些依赖关系。

页面

因此,实现前端资源治理的第一个要点是做好页面管理,把页面自身的信息,如页面名称、页面地址、负责人、修改时间等信息进行提取、存储,使之能够被查询和检索。在页面管理基础之上,我们还要把js、css、图片、页面、后端接口、配置数据、监控点等各个前端资源之间的关联关系也要存储和管理起来,使之能够被查询和检索。

关联关系从来源上讲,主要有以下几种来源:

  1. 代码静态分析产生。通常包括页面信息自身、页面跟js/css/图片等的依赖关系、页面跟接口的依赖关系等。
  2. 管理端配置产生。通常包括页面跟监控系统的配置、页面的运营配置数据等
  3. 统计数据产生。通常包括页面来源数据等。

关联关系管理

2.1 页面信息的提取

前端资源治理的第一要点是页面信息管理,因此必须能够拿到页面基本信息。页面基本信息应该包括哪些呢?通常来说,至少应该包括页面URL、页面名称、页面创建人、创建时间等几个字段。

当前的前端页面开发,不管是H5、小程序,还是原生APP,通常会经过编译构建的过程(通常是命令行工具或者IDE,比如基于gulp和webpack的工作流工具),在构建完成阶段可以提取出页面的基本信息。以下是编译构建提取页面信息的流程:

页面信息的提取

页面的编译构建流程,一般分为两种:

  1. 独立构建。常见于H5,此种场景一般是一个人负责一个页面,不存在多人协作的情况,也不需要git分支管理啥的,开发完成即可走构建流程,只需要在构建完成的时候分析即可,页面的URL、页面标题、创建人、创建时间等信息比较容易提取,比如页面修改人可以取自命令行工具的用户登录身份(命令行工具可以做类似于NPM的login功能,登录后记录用户身份ID)、页面标题可以解析页面html的title的内容(小程序下则解析自页面json文件的navigationBarTitleText字段)等。
  2. 持续集成构建。这种一般是需要多人协作的H5、小程序、原生APP等,一般涉及到分支管理和合并的问题,同一个页面可能被多人修改,因此页面信息中的用户信息部分提取相对复杂,需要分析git log信息才能拿到,其他的信息字段提取逻辑与独立构建情况相同。 以下是一个典型的多人协作的页面的git log信息。

对于上面的情况,我们可以考虑定一个规则,比如取最近的5条log,并移除持续集成系统生成的log,管理端存储的时候回,以用户名+时间为key,去掉重复的部分。

构建流程分析出页面基本信息后,需提交到管理端保存,所以管理端需要提供post接口。管理端以此为基础,形成”页面管理系统“。

2.2 代码静态分析出的关联关系

构建流程除可以分析基本信息外,还可以分析出页面的版本信息,比如页面依赖的组件依赖表、静态资源依赖表(js/css/图片)、接口依赖表、修改人、修改时间等。 静态依赖分析通常有3种方式:

  1. 基于AST的依赖分析。 AST就是抽象语法树,目前前端对他的研究和使用越来越广泛,webpack内部就使用了acorn这个AST分析库。借助于webpack强大的模块解析和依赖分析能力,我们可以拿到js与npm组件、css与背景图等之间的关联关系(可以在webpack的after-resolve钩子中进行分析)。另外,除了构建前的依赖关系,我们还可以拿到构建处理后的资源依赖关系(可以在webpac的emit钩子中进行分析),前者我们称为引用依赖关系(包括静态资源依赖表、组件依赖表),后者我们称为发布依赖关系。
  2. 基于DOM操作的依赖分析。 webpack并不是以html为入口的,但是实际上我们的开发的入口可以认为就是页面,借助于JsDom等强大的类库,我们可以用我们熟悉的前端的DOM操作来分析html页面对js、css、图片等的依赖关系。
  3. 基于正则匹配的依赖分析。 页面对于接口的依赖分析,由于这种是非明确的代码依赖关系,所以一般通过正则匹配来解析。一般对代码有一定的约束规则,比如不用用变量拼接接口地址。这个解析不会如AST那么精确,但是只要约定规则,基本上都能满足需求。可以考虑把此类实现封装为webpack的loader。
    关联信息的提取
    上面的第一种和第三种的分析,都应该是一个递归分析过程,最终生成页面的静态资源依赖表、组件依赖表、接口依赖表等。这些信息提交到管理端进行保存。

2.3 管理系统之间的关联关系

在很多互联网企业,通常已经有一些独立的成熟的CMS系统(如给运营用的内容配置系统,配置活动时间、商品ID等)、监控系统(如测速系统、业务监控系统、异常监控系统)等,通常这些系统由不同的团队开发,而且经常都有一个叫做"页面管理"的东西,且要手工配置页面地址。这些系统中的监控点配置、运营配置等信息,都是以页面维度进行创建和使用的,但是这些信息很难通过对前端代码静态分析的方法进行提取(比如运营配置信息,这个可以是前端直接使用,也可能是后端使用,要分析的话两端代码都要分析,比较麻烦)。我们的思路应该是在管理端通过页面管理来进行关联,实质上是要做系统整合。

整合的思路也比较简单,就是原来各个系统废弃掉原来自身的”页面管理“,而是使用前面静态分析提取到的统一的页面管理,监控系统、运营配置系统等系统都可以以此为入口进入,从而把页面相关的各个管理系统关联起来,进而把各种能力串联。

管理系统的关联

2.4 统计数据产生的关联关系

对于大型应用来说,一般都有一些业务统计数据,最典型的就是点击流数据了。这种数据既不在代码中,也不在管理端配置,而且通过统计和分析才能拿到。前面提到的“某个限时的页面已经到点下线,但是仍然有流量,不知道流量入口在哪里”这种问题的解决,其实依赖于点击流的统计分析数据了,点击流系统一般都有“来源分析”,这种数据也不是敏感数据,所以可以考虑跟页面管理做关联和整合,或者提供API给页面管理系统。另外还有一个例子就是,接口和页面的关联关系,前面提到通过静态分析得到的页面和接口的依赖表有可能不够准确,但是接口访问Web Server的时候,一般都有access.log,可以通过access.log来做分析,拿到比较完整的页面依赖的接口信息,以及接口依赖的页面信息,有些接口的调用需要有open api的那种注册调用机制,就另当别论了。

统计系统的关联

2.5 关联关系的查询和存储

管理端应该提供正反两个方向的查询和检索能力:

  1. 正向查询。通过页面来查询依赖的组件、静态资源(js/css/图片)、后端接口等。此种比较简单,因为提交的时候已经有完整的依赖信息,只需要提供简单的查询。
  2. 反向查询。通过组件、静态资源、接口、运营配置信息、监控配置信息等,反查有哪些页面依赖。

对于关联关系的存储,用关系型DB的话,一般只能使用like查询,可能要扫描全表,因而性能比较差,可以考虑存储到MongoDB中创建索引,或者存储到ElasticSearch中建立索引。

2.6 其他

前面提到的,其实有一个假设的前提“只有一个Web应用,且接口都是前端发起的”,但是对于其他情况,思路是类似的:

  1. 多应用(业务)。多应用情况,通常要在页面管理的上一层加上“应用管理”,即页面属于哪一个应用(业务)。对于同一个页面投放在不同应用的场景,可能页面还得加上渠道标识。
  2. 页面直出(服务端渲染)。对于页面直出逻辑的代码,做前面类似的分析即可。 另外,本文主要是探讨从前端视角考虑问题,所以关联核心是页面管理,但是从整体技术架构视角,可能就不是了。

3.结语

本文探讨了前端资源治理的含义以及要解决的问题,并介绍了实现前端资源治理的思路,是笔者近期在前端工程化方面的思考,部分已经完成,部分正在推进。本文并不涉及实现的细节,细节在后面的系列文章中进一步讲解。 前端治理的两个关键点,一个是系统整合,一个是关联关系管理,整体串联的核心是页面管理。


如果你觉得这篇内容对你有价值,请点赞,并关注我们的官网和我们的微信公众号(WecTeam),每周都有优质文章推送:

WecTeam