原文地址:https://juejin.cn/post/7370197993679355954
作者:生姜拿铁
去年年初接手了一个B端项目,经历了几个月的开发之后,发现了一些问题,严重的影响了前端的开发效率和上线质量。当时业务迭代快,前端人力又少,因此,我们专门立了一个技术项目,来对现有的系统进行一个渐进式的工程化治理。
选择什么样的工程方案
社区内对于前端工程化方案已经有一些'一揽子式'的解决方案。比如next,umi,我们公司其实也有一套方案。但是这些方案普遍存在的问题,
-
-
定制化难度大。因为是黑盒,遇到问题几乎只能等官方支持。
-
臃肿。因为这些一揽子方案要适配各种场景,因此会有很多不需要的依赖和配置,比如我们公司的方案会有很多上报的服务。
综上,我们选择了针对自己项目的方案,一个点一个点的去解决问题。
规范
-
代码规范。这个较为常见,网上也有很多教程,没有什么干货,重要的是取舍一些规范。一个我认为较为重要的点,是目录结构和接口的命名规范,这在后期的维护上会节省很多成本。
-
前后接口规范。这个是与后端团队协商出来的规范,包含一些统一的错误码,数据结构,数据类型,通用的字段名称等。这个规范能保证接口的可联调性。
-
协作规范。这个是涉及到产品上线的全链路流程,比如需求的准入要求,转测的验收标准,上线的SOP等。这些是需要跨团队沟通和确定的。
-
交互规范。这个是与产品协商的,通用的交互规范,便于组件的沉淀和复用,降低开发的难度和成本。
基础建设升级
打包工具升级
项目的打包工具还是webpack3.X。经过调研之后,没有使用vite和webpack5,而是直接选了当时发布不久的rspack。
主要是基于以下几点考虑:
-
vite 没有想象的快,启动很快,但是首页白屏时间还是要很久。并且,线上线下的底层打包工具不一致,不好发现问题。
-
webpack5 很好,但毕竟还是基于node,随着代码量的增多,打包时间还是会逐渐再次增长。相比之下,rspack使用rust来实现,在这种计算密集的场景下,性能和node不是一个级别的,即使代码增多,打包时间所受的影响也较为轻微。
-
rspack已经经历了字节内部的检验,并且编译核心也是久经考验的swc。打包工具的升级,带来了非常好的效果。我们的发布流水线,一下子从20分钟,缩短到了8分钟。平均每个月为开发者节约80hour。
当然这个过程并不是一帆风顺的,当时的rspack还是有一些插件的兼容性问题,但还好官方回应快,自己也就很快解决了。
包管理器升级
原有的包管理器是yarn2.X,我们升级到了pnpm。
pnpm的好处不用多讲,总之就是快,而且切换成本低。
同时,我们对项目中重复的包,无用的包进行清理。使得最终我们的node_moudle从2个G,缩小到700多M。但遗憾的是,我们公司的发布流水线不支持pnpm。因此我们专门写了适配的插件,并加上了服务器缓存,在缓存命中的情况下,包的安装时间只有3秒。
改造完成后,我们的线上发布时间,在缓存不命中的情况下,也缩短到了4分钟。
堪称极速,开发体验也大大提升。
采用monorepo
我们的业务有多个系统,由于是服务同一个业务,因此有很多数据类型,组件,接口都是可以复用的。
但我们现有的系统代码,是分散在不同的仓库中的。如果要想复用,往往就是从其他地方直接复制过来,改改就用了。
这一方面会有潜在的质量问题,一方面也违反DRY 的工程原则,难以治理。
使用monorepo,就可以很好的解决跨系统的组件复用问题。
我们采用了lenra方案,新增可以中间依赖的包,存放这些可服用的资源。一年下来,沉淀了有70多个组件,复用次数达500多次,开发提效约20%。
物料建设
常用组件沉淀
由于我们公司并未采用antd这样的较为成熟的社区组件,因此许多业务组件,都需要自己建设。而B端业务,大部分都是增删改查,因此我们针对通用场景做了标准化组件建设。
一方面,我们针对自己的业务特性,对这些组件进行功能增强或者样式改善,比如给Form加上不同类型的布局。
另一方面,我们对于相似场景的组件,进行了配置上的统一。
比如Form,Table,Description这样的组件,都需要配置所显示的label,对应的数据字段名,以及显示成什么样子。我们将这些组件的字段配置统一起来,这样提升了组件的可配置性,配置文件的可复用性等。
VScode插件开发
由于组件配置上的一致性,很便于做一些模版填充。因此,我们又做了一个VScode的插件。
它内置了一些代码模版,比如复杂的CRUD,编辑表单,编辑页面等。
当用户选中一些TS的类型时,它 可以读取这个类型中包含的字段,生成配置代码和mock数据,填充到内置的模版当中。
填充好的代码是直接可以运行的,只需要调整一下适配的字段,真实请求的接口即可。
普遍场景下,开发者在几分钟内就可以完成一个CRUD页面的开发。达到了低代码一样的效果,但又避免了低代码带来的种种问题。
技术治理
领域建模
DDD是后端比较流行的概念,其涉及的内容较多。作为前端,我们借鉴了其中一部分的思想。
我们业务包含了一些常见的业务流程,比如采购,营销,财务等。
我们将这个完整的流程,作为一个领域,进行TS建模。这个建模尽量与后端的建模保持一致,便于进行数据交互。
在单一领域内,数据的类型的固定且通用的,就是我们所说的Model层。
而具体到页面,我们新建一个ViewModal,使用ViewModal来完成页面的交互。
Model层和ViewModel层是紧密联系的,我们采用AOP的方式,来对这两种结构进行自动转换,降低开发成本。
这样的设计带来的好处是:
-
-
-
当然,其前期建设的成本是比较高的,而且要写一些冗余代码。但是考虑到收益,这是值得的。
低代码替换
由于历史问题,很多页面采用了JSON Schema进行低代码渲染的方式。低代码的页面,不仅性能差,小问题多,而且难以复用和维护。因此,在做新需求时,如果与产品确认,该页面后续需求很多,复杂度较高,那么就会考虑将该页面重构为原生React。在物料和插件的加持下,这种改造成本很低,但是需要做规划和测试。
静态代码分析
日常的开发中,由于各种文件互相引用,在进行开发的时候,极易产生意料之外的影响。同时,由于我们会重构一些低代码页面,因此项目中也存在很多不被使用的无效文件。我们开发了一个工具,它可以根据路由配置,然后一层层的往下递归文件,便于我们分析出无效文件,保持项目的干净度。当有文件变动时,也能层层向上访问,分析出该文件会影响到哪些路由和页面,便于我们进行回归和测试。
总结
我们的治理之路,与社区中主流的方案有一部分是重合的,有一部分则是独创的。但他们的目标是一致的,事实上,经过一年的建设和使用,我们的开发效率和质量都有不小的提升。