本文转载于稀土掘金技术社区,作者:厚礼蟹man
最近在忙公司前端基础建设的架构设计,头发快掉光了。说是基础建设组,实际就我一个人,我哭。。。虽然还在陆续招人中,招不到人我就“噶”给公司看👻
背景
公司有五条业务线,每条业务线技术栈都比较封闭。做工程化之前,我对每条业务线做了一次技术摸底,发现问题不少:
项目框架类型复杂多样,老旧( cra, umi, vite, uniapp, taro, react, vue
)工具类型繁多( mobx,redux,dva,pinia,taro-ui,nutui,antd-mobile
)TS
应用较少hook
使用意识淡薄基础建设薄弱,目前只有各自的组件库 提效手段稀少 文档稀缺 node
服务开发经验稀缺(BFF,SSR
)工程数量繁多(5条业务线总共近200个,高频维护的也有60个左右),无持续优化手段 无横向技术共建手段
不能说不太行,只能说惨不忍睹。。。
今年公司在布局AI
,新项目层出不穷,对基础建设的述求越来越强烈,看来是时候出手整顿下基建了
目标
统一技术栈: React,TypeScript,Vite
统一规范:工程规范、构建规范、lint规范、代码规范 提高开发效率: cli
自动化、mock
数据、代码片段、页面模板等渐进式可持续优化
分析
分析之前我想先引用《前端架构设计》中的一句话:
前端架构是一系列工具和流程的集合,旨在提升前端代码的质量,并实现高效、可持续的工作流。
然后我们在网上搜下“前端工程化”:
提取关键信息:模块化、组件化、自动化、规范化
我个人认为:
架构设计是一种设计模式,可以根据不同应用场景而变化,设计范围可大可小,比如: BFF
的架构设计、CLI
的架构设计工程化是一种应用场景,每个公司的工程化实现都各不相同,原因在于架构设计的不同
总结来说就是,基于某一种架构设计来实现工程化
回顾工程化提取出来的几个关键词,可以发现工程化解决了架构设计里的代码质量和高效两个点,那第三点的可持续应该怎么去理解呢?
我个人觉得可持续可以调整成渐进式优化会更合适一点,在工程化场景我把它分成两个方面:
旧工程如何逐步接入工程化能力,优化开发流程和体验 工程化能力如何持续优化
结合公司现状,我调整了一下关键字:规范化、模块化、自动化、渐进式,下面就来拆解下这几个关键字
分而治之
架构图
先对上面的12字真眼(箴言)进行简单说明
规范化(基础):不仅仅是 lint
规则、代码规范,而是每个项目的同一环节使用同一套解决方案模块化(设计):将每个环节的解决方案以 npm
包的形式提供,可以将npm
理解成模块自动化(应用): CI/CD
,CLI
不仅提供项目模板的功能,还能对npm
包的进行升级以及配置调整渐进式(核心):功能模块化持续更新、间歇性重构更新
规范化
规范的重要性我在这边就不过多阐述了,大家都懂得。外加两个公司特性:经常会有跨业务线支援的场景,可能会有做Taro
的去其他业务线支援uniapp
项目的;基于上个特性,就大概率会出现屎山代码、一个项目有两种状态管理工具。
那究竟是因为有屎山导致人力不够要支援呢?还是因为支援了导致屎山变大了?这是个哲学问题(沉思~、~)
所以规范化要做的几件事:
统一技术栈, React、TypeScript、Vite
(umi,taro
编译器选择vite
)根据项目类型统一应用框架,后台: umi
;多端:taro
;微前端:qiankun
;SSR
:next
;BFF
:koa
;npm
:vite
代码规范:前端规范可以这样做[1]
模块化
目前规划了以下几个模块:
pack
:基于应用框架构建配置进行二次封装,能力范围只做基础配置和构建优化lint
:alloy
+公共规则+业务团队规则,husky
考虑到开发水平参差不齐,决定权交给业务团队micro
:提供微前端配置和通讯方案aegis
:因为公司使用的是coding
,所以并未使用其他商业监控方案或自己搭建,使用的是coding
提供的监控方案
为什么没有组件库?因为我们五条业务线行业跨度较大,UI
风格目前达不到统一,组件库由各个业务线自行封装,基建组提供组件库工程模板,包含构建、SSG
文档、单元测试等基础功能
自动化
CI/CD
采用的是coding
的云原生构建部署,docker
容器、k8s
镜像啥的有专业的运维团队在维护,前端只是写写配置脚本,这里就不展开说了
重点说下CLI
,我把CLI
和插件规划在提效体系下,这里的插件包含浏览器插件、vscode
插件等外部工具的插件,不包含pack
插件、lint
插件等内部工具的插件
CLI
cli
采用的是插件架构设计(看,这边也出现了架构设计),插件架构得益于它的高稳定性和高拓展性,在保证核心程序功能稳定的前提下,丰富了CLI
的能力,目前规划的能力有:
针对各个 npm
模块提供快速升级和调整配置的能力,省去使用方介入成本近99.999%
快速生成各种项目类型的工程模板 自动生成 api
接口的TS
类型和mock
数据,注意,这两个是关联关系。我调研了umi
的mock
能力,它的弊端在于未打通TS
类型和mock
数据,TS
类型可以通过一些库根据接口文档自动生成,但mock
数据还需要开发自己根据类型手动定义,十分麻烦。另外也调研了apifox
,apifox
能力很强大,弊端在于需要一定的人工成本,无法深度集成进工程体系中。所以规划实现一个根据接口文档自动生成TS
类型,再根据接口类型自动生成mock
数据,mock
能力使用的是umi
提供的mock
能力,这样就做到了自动化和深度集成。
vscode
插件
想必大家都听过这两个词,”代码片段“、”页面模板“
代码片段其实运用到的是vscode
的snippets
能力:
代码片段好处在于提效和规范,提效容易理解,规范怎么说呢?前端在做代码规范的时候常常会定义一些命名规范,这时候靠人为去记或者CR
的时候去纠正是很费时间精力的,这时候通过预定义好的一些代码片段,就能够很好的达到命名规范的要求了
页面模板其实就是通过node
脚本去生成预定义好的一个页面文件(夹),实现方式可以有多种
可以通过cli
生成,比如nestjs
的cli
umi
的微生成器,实际上也是通过cli
生成
又或者可以在项目中自定义页面模板,然后写个node
脚本去生成
方法很多,但有个通病,对目录结构要求很严格,且模板类型有局限性,比如我对components、hook、page
都想生成一份各自对应的模板出来,阁下要如何应对?
这时候引出vscode
插件就很妙(妙啊~,~),取长补短
取长:插件内置通用性模板,也支持项目中定义业务性模板,同理snippets
也可以做成内部和外部的片段
补短:利用vscode
的右键菜单能力,精准定位目标目录
但,vscode
插件就目前的人力情况是没办法重新写一个了,只能先用之前写的vscode 插件 --- xy-quick 介绍[2]垫垫了,设计上有些欠缺(目前已不在这个公司了)
浏览器插件
目前没有需要用到浏览器插件的功能,只是预留了这个口子
渐进式
架构设计的三大原则:合适原则、简单原则、演化原则,其中演化原则就是渐进式设计的指导思想
只有变化是永恒不变的,没有一个框架可以一直使用下去而不升级迭代,如何降低版本升级的摩擦成本是每个框架必须要考虑的问题,也就是渐进式,所以我把它标记为核心
我个人认为将功能拆分成模块/插件进行管理在工程化方面是最优选择(有其他见解的欢迎在评论区讨论噢~)
渐进式在这个架构中有两个方面的实现:
模块化
思考一个问题:你是怎么拆解你的项目的,怎么做项目优化的,如果有多个同类型的项目,是怎么做持续优化的
我的方案是将每个独立且可复用的功能提取出来以npm
的形式进行管理,也就是上面提到的pack、lint、micro、aegis
,这样只需要升级版本和略微调整配置就可以实现持续优化。重点在于我们的npm
包要做到什么程度上的配置收敛,是做成umi
的开放式还是cra
的封闭式?举个例子:基于umi
的umi-pack
包,我们是使用scss
还是less
、是否打开mock
、允不允许打开webpack
构建(因为我们设计底层构建工具使用的是vite
),这个就是基建和业务的碰撞,需要权衡清楚
CLI
CLI
采用的是插件架构,利用其核心稳定性和高拓展性,很好的满足了能力上的拓展,模块搭配cli
升级,直接将版本升级的摩擦成本降低至0.001%
,完美~
渐进式在工程接入也有两个方面的表现:
老旧项目:单个模块逐个接入,逐步改造
工程化项目:单个模块逐个升级,逐步优化
不足
AI
能力的集成,会持续关注可集成场景对 coding
平台的运用还不够深入,会持续关注可集成场景
做基础建设需要考虑的一些点
技术选型自不必说,关系到之后技术路线的发展 做基建的根本目的是为了服务于业务,在设计之初是否做了充分的技术摸底和业务思考,比如是否启用 husky
、node
版本控制核心仓库应该如何设计 新规则与现有规则的取舍/融合
后话
如果你有耐心看到这里,可能会有一些疑问,你这工程化里没有低代码、跨端方案吗?
首先,我想称赞你很有想法(川普肯定了你表情包)
其次,我个人认为低代码、跨端是属于系统级别的工程化,我目前所设计的是应用级工程化,工程化亦有差距
最后,个人水平有限,此文旨在抛砖引玉,引发大家对工程化的思考,欢迎大家在评论区讨论