【必看】前端工程化治理之路

哈喽大家好,我是Fine。

在工作中作为一个前端开发,不止是要会写业务,如果想拔高,前端工程化也是必经之路。

以下是正文:

去年年初接手了一个B端项目,经历了几个月的开发之后,发现了一些问题,严重的影响了前端的开发效率和上线质量。当时业务迭代快,前端人力又少,因此,我们专门立了一个技术项目,来对现有的系统进行一个渐进式的工程化治理。 

选择什么样的工程方案

社区内对于前端工程化方案已经有一些'一揽子式'的解决方案。比如next,umi,我们公司其实也有一套方案。但是这些方案普遍存在的问题,

  1. 迁移成本高。因为是一揽子方案,要做很多适配工作。

  2. 定制化难度大。因为是黑盒,遇到问题几乎只能等官方支持。

  3. 臃肿。因为这些一揽子方案要适配各种场景,因此会有很多不需要的依赖和配置,比如我们公司的方案会有很多上报的服务。

综上,我们选择了针对自己项目的方案,一个点一个点的去解决问题。

规范

规范是实施成本最低的一个节点,但其实收益是很大的。网上的很多教程,往往是局限于前端的一些规范,这是远远不够的。

在实际的开发过程中,我们需要与后端,测试,产品一起协作,不能仅限于前端的代码规范。

我们先后确定了以下的规范:

  1. 代码规范。这个较为常见,网上也有很多教程,没有什么干货,重要的是取舍一些规范。一个我认为较为重要的点,是目录结构和接口的命名规范,这在后期的维护上会节省很多成本。

  2. 前后接口规范。这个是与后端团队协商出来的规范,包含一些统一的错误码,数据结构,数据类型,通用的字段名称等。这个规范能保证接口的可联调性。

  3. 协作规范。这个是涉及到产品上线的全链路流程,比如需求的准入要求,转测的验收标准,上线的SOP等。这些是需要跨团队沟通和确定的。

  4. 交互规范。这个是与产品协商的,通用的交互规范,便于组件的沉淀和复用,降低开发的难度和成本。

基础建设升级

打包工具升级

项目的打包工具还是webpack3.X。经过调研之后,没有使用vite和webpack5,而是直接选了当时发布不久的rspack。
主要是基于以下几点考虑:

  1. vite 没有想象的快,启动很快,但是首页白屏时间还是要很久。并且,线上线下的底层打包工具不一致,不好发现问题。

  2. webpack5 很好,但毕竟还是基于node,随着代码量的增多,打包时间还是会逐渐再次增长。相比之下,rspack使用rust来实现,在这种计算密集的场景下,性能和node不是一个级别的,即使代码增多,打包时间所受的影响也较为轻微。

  3. rspack已经经历了字节内部的检验,并且编译核心也是久经考验的swc。

打包工具的升级,带来了非常好的效果。我们的发布流水线,一下子从20分钟,缩短到了8分钟。平均每个月为开发者节约80hour。

当然这个过程并不是一帆风顺的,当时的rspack还是有一些插件的兼容性问题,但还好官方回应快,自己也就很快解决了。

包管理器升级

原有的包管理器是yarn2.X,我们升级到了pnpm。
pnpm的好处不用多讲,总之就是快,而且切换成本低。
同时,我们对项目中重复的包,无用的包进行清理。使得最终我们的node_moudle从2个G,缩小到700多M。但遗憾的是,我们公司的发布流水线不支持pnpm。因此我们专门写了适配的插件,并加上了服务器缓存,在缓存命中的情况下,包的安装时间只有3秒。

改造完成后,我们的线上发布时间,在缓存不命中的情况下,也缩短到了4分钟。

编译工具,包管理的升级,最终使我们的单次发布时间,从20多分钟,一次性降低到4分钟左右。堪称极速,开发体验也大大提升。尤其是在ST阶段发现问题时,修复时间大大缩短,不会影响到最终的上线时间。

采用monorepo

我们的业务有多个系统,由于是服务同一个业务,因此有很多数据类型,组件,接口都是可以复用的。
但我们现有的系统代码,是分散在不同的仓库中的。如果要想复用,往往就是从其他地方直接复制过来,改改就用了。
这一方面会有潜在的质量问题,一方面也违反DRY 的工程原则,难以治理。
使用monorepo,就可以很好的解决跨系统的组件复用问题。
我们采用了lenra方案,新增可以中间依赖的包,存放这些可服用的资源。一年下来,沉淀了有70多个组件,复用次数达500多次,开发提效约20%。

物料建设

常用组件沉淀

由于我们公司并未采用antd这样的较为成熟的社区组件,因此许多业务组件,都需要自己建设。而B端业务,大部分都是增删改查,因此我们针对通用场景做了标准化组件建设。

在做组件时,我们着重做了以下一些事情:

  1. 抽取高频组件,并遵循交互规范。没有交互规范的,则拉产品和设计,对齐出一版规范来。

  2. 统一化配置。比如Form,Table,Description这样的组件,都需要配置所显示的label,对应的数据字段名,以及显示成什么样子。我们统一使用{props:'name',label:'姓名',type:'input'}这样的配置字段,这样可以复用配置字段。

  3. 内置一些常用组件。比如使用{type:select},就表示渲染成一个select,这与Xrender非常相似。但是因为我们饱受低代码的荼毒,所以我们的自定义渲染,采用了函数式的配置,使得用户使用原生的方式来解决状态联动的问题,避免使用wacth,depend之类的配置。平衡配置化和定制化的程度。

VScode插件开发

由于组件配置上的一致性,很便于做一些模版填充。因此,我们又做了一个VScode的插件。
它内置了一些代码模版,比如复杂的CRUD,编辑表单,编辑页面等。
当用户选中一些TS的类型时,它 可以读取这个类型中包含的字段,生成配置代码和mock数据,填充到内置的模版当中。
填充好的代码是直接可以运行的,只需要调整一下适配的字段,真实请求的接口即可。
普遍场景下,开发者在几分钟内就可以完成一个CRUD页面的开发。达到了低代码一样的效果,但又避免了低代码带来的种种问题。

技术治理

领域建模

DDD是后端比较流行的概念,其涉及的内容较多。作为前端,我们借鉴了其中一部分的思想。

我们业务包含了一些常见的业务流程,比如采购,营销,财务等。

我们将这个完整的流程,作为一个领域,进行TS建模。这个建模尽量与后端的建模保持一致,便于进行数据交互。

在单一领域内,数据的类型的固定且通用的,就是我们所说的Model层。

而具体到页面,我们新建一个ViewModal,使用ViewModal来完成页面的交互。

Model层和ViewModel层是紧密联系的,我们采用AOP的方式,来对这两种结构进行自动转换,降低开发成本。

这样的设计带来的好处是:

  1. 逻辑解耦,易于维护

  2. 领域内的重复建设会收敛,有助于提效

  3. 单一领域内的理解成本会降低,新人接手的成本也低

当然,其前期建设的成本是比较高的,而且要写一些冗余代码。但是考虑到收益,这是值得的。

低代码替换

由于历史问题,很多页面采用了JSON Schema进行低代码渲染的方式。
低代码的页面,不仅性能差,小问题多,而且难以复用和维护。
因此,在做新需求时,如果与产品确认,该页面后续需求很多,复杂度较高,那么就会考虑将该页面重构为原生React。
在物料和插件的加持下,这种改造成本很低,但是需要做规划和测试。

静态代码分析

日常的开发中,由于各种文件互相引用,在进行开发的时候,极易产生意料之外的影响。同时,由于我们会重构一些低代码页面,因此项目中也存在很多不被使用的无效文件。
我们开发了一个工具,它可以根据路由配置,然后一层层的往下递归文件,便于我们分析出无效文件,保持项目的干净度。
当有文件变动时,也能层层向上访问,分析出该文件会影响到哪些路由和页面,便于我们进行回归和测试。

总结

我们的治理之路,与社区中主流的方案有一部分是重合的,有一部分则是独创的。但他们的目标是一致的。

需要注意的是,我们的整体治理的逻辑,是一环套一环的,比如有了组件,才有了插件,进一步才有了低成本的低代码 替换,而因为替换的页面多,才会有静态代码分析的必要。

整体来说,也还算是一个体系化的治理。

经过一年的建设和使用,我们的开发效率和质量都有不小的提升。

原文地址:https://juejin.cn/post/7370197993679355954

侵删

最后

还没有使用过我们刷题网站(https://fe.ecool.fun/)或者前端面试题宝典的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。

我们团队的前端辅导也做了将近2年了,陆陆续续辅导了几百位同学,分享一下最近几个结束辅导的回访。