我理解的前端工程化
前言
现在越来越多的前端人员都在聊前端工程化。可能很多初学者认为前端工程化就是我会使用webpack,我能够使用某些cli工具来搭建我们公司的项目等等;也有一部分的人认为前端工程化就是涵盖了前端从立项到上线过程中的每一步,前端的每个项目即是前端的一个工程在前端工程中包含有项目的创建过程,开发过程,测试过程,上线过程等一系列的工作流程的内容等。
那么什么是前端工程化?对于这个问题,我这里就从我个人的角度来聊一下,这个前端工程化的内容。
前端工程化的由来
对于前端开发来说从最初的切图仔到现在的可以称为前端工程师的称呼上面,可以看出,前端在整个web端的的地位在逐渐的提升。当然提升的也不仅仅是称呼,更重要的是前端的开发理念加开发流程的整体的发展。
刀耕火种时代
很久以前其实前端的工作其实还是很简单的,就是讲UI的设计图转换成网页,并且写一部分的JS来控制页面中的交互内容,不用去管后期的数据渲染什么的。而且以前的前端开发流程也很简单,就是自己切好图,丢给后端的同学就好了,至于套页面等的工作就不用管了,毕竟哪些工作都只是后端同学的事情了。当然也有一些企业单位会让前端去写渲染层的东西,让前端使用php,jsp,asp等技术,来完成前端的工作(这样前端同学在换工作的时候,由于后端使用语言的不同,可能就需要学习各种的后端框架以及各种的模板引擎)。
其实不管是哪种实现的思路,前端这边的仍然是一个比较简单而且重复的工作。“简单”,其实就是说白了就是切图,排版的内容,哪怕是后续套页面的工作(当然这些都是一些中小型项目);“重复”,就是说前端中有很多通用的东西,前端要做的就是各种拷贝,每一次的拷贝生怕有任何一点的遗漏。随着项目的发展,前端的项目是越来越大,后期的维护成本也越来越大,前端这边的改动成本也会越来越大, 就可能需要前端去处理后端数据的问题,或者是需要后端来解决前端的问题,这样的这样不仅仅操作的难度大,而且,对于双方都不友好。
发展阶段
后来有人想到了前端中存在一个被叫做ajax(Asynchronous JavaScript and XML)的东西,这个东西可以实现前端跟后端的通信,这样,就能够将前端的项目进行单独部署,然后后端单独部署,这样就实现了完美的前后端分离的工作。瞬间,就像发现新大陆一样,很多企业都开始实行这样的模式了,只是部署的方式可能有些不同,有的是直接将前端的页面和资源直接扔到nginx中,作为一个静态资源服务器,将网站指向到html文件中;有的是将前端的项目直接放进项目里面,不管是作为静态资源还是作为view资源,然后通过建个Controller的方式再进行访问到页面的文件等。都是为了将前后端的工作进行分离开来,早点脱离修改其他人代码的烦恼。
鸟枪换炮时代
前后端工作分离开始之后(这个不是很准确),接着就是前端重复内容的问题。对于重复内容,不管是html中的内容还是JavaScript中的内容,等等这些东西,还是需要拷贝。但是对于使用了模板引擎的项目来说可能稍微会好一些,可以使用includes来引入公共的部分,但是对于js来说不行。如果将每个细分的功能模块都写入到一个js文件中的话,就会造成整个js比较大,另外还有可能造成全局污染问题。于是一些优秀的前端工程师们决定向后端取经,提出了模块机制。早期,这种模块机制在Dojo、EXT这些框架中都是内置的,但是显然说服不了另一个框架的用户用对方的模块机制,于是有人立志要统一这种模块定义方式,成立了CommonJS。但是CommonJS内部也有派系,谁也说不服对方。终于有一个人忍不住自己独立开发出RequireJS,其模块规范即为AMD。AMD最大的优势是它支持各种插件,且简单明了,并且提供shim机制加载以非AMD规范编写的JavaScript代码。接着就是NodeJs的诞生,伴随着NodeJs的诞生,同时也推出了不少的前端打包工具,grunt,然后就是gulp。
质的飞跃
对于前端开发,仅仅将分模块开发的代码打包到一起能够解决一部分的问题,但是整个过程的运行什么的还是基于文件系统的,并不能够完全模拟一个网络环境。如果要模拟一个网络环境,就需要一个服务器的载体,或者是nginx,jsp,亦或是php等等,但是这些对于前端来说又比较的陌生,同时由于nodejs的发展,进化出了基于node的前端服务器框架express。因此就有人想,能否基于node服务来提供服务器载体,并且,将打包功能集成进去。这个时候,webpack就应运而生了。同时webpackt提供热更新功能,webpack是一个比较开放的东西,大家都可以为其添加不同文件的编译工具(loader),并且用户可以根据自己的需求,将其进行改造,形成自己的一套完整的开发体系。因此webpack迅速的占领了整个前端的工具链的市场。
完整体系的建立
渐渐地像vue,react和angular框架的逐渐推出和完善,都各自提供了模块发的开发,组件的共用,大大的提高了前端开发人员的开发效率。另外各个框架都有推出自己基于webpack的cli工具,统一了他们的工程化开发流程,从dev到build等。这样一来,导致很多的前端同学都觉得,前端工程化就是webpack。后续有推出了很多的打包工具,比如说rollup,vite等,都是为了帮助前端同学提高工作效率。另外很多前端根据自己的工作需求,开发了不同性质的前工程化工具,并将前端工程化推向了一个高潮。近两年,各种低代码平台的呼声越来越高,其实低代码也算是前端工程化的一个范畴。
低代码时代
近两年,各种低代码平台的呼声越来越高,其实低代码也算是前端工程化的一个范畴。前端工程化的目的就是为了提高前端的开发效率的问题,而低代码平台的目的也是提高前端的开发效率,并且低代码的实现方案是基于之前的模块化打包方案,以及打包工具,和各自的框架,只是能够使开发者能够所见即所得,而且就算不懂前端,也能够简单的配置一下,来实现自己的想要的功能。这样的前端开发者只需要按照需求,来定制化的开发一些组件,以及将大多数的精力放在工具的优化和开发使用上面。这样开发的工作量低了,沟通以及信息的传递的损失以及时效性所带来的的成本,也会随着低代码平台的完善,逐渐的降低。
什么是前端工程化
“工程”一词源于十八世纪的欧洲,最早是使用在兵器制造、具有军事目的的各项劳作,后拓展到多个领域,比如建筑屋宇、机械制造、架桥修路以及软件开发。在在现代社会中,“工程”一词有广义和狭义之分。就狭义而言,“工程”定义为:以某组设想的目标为依据,应用有关的科学知识和技术手段,通过有组织的一群人将某个现有实体转化为具有预期使用价值的人造产品的过程。说白了“工程”就是指从有想法,到将想法转化为实际的东西的过程。那么“工程化”也就是应用于实体产生的整个过程。
有关前端工程化的概念,就是将前端项目(或者想法)转化成实际能够使用的应用的整个过程。换句简单点的话说就是从立项到开发再到最后的上线的整个过程,就是前端工程化。
那么在这个过程中,前端开发者都做了哪些事情呢?
- 设计方案和技术选型
- 开发规范设计
- 接口通用规范的约定
- 项目的搭建,创建git托管
- 功能拆分,组件拆分
- 基础组件的开发
- 业务功能的开发
- 后端接口对接联调自测
- 提测
- bugfix
- 打包上线
- 后期维护
我理解的前端工程化,至少应该包含有上述过程的,才能算是整个工程化。就好像我们刚初出茅庐的时候,拿到一个需求(可能是一堆的设计图),就开始切图铺页面,当页面铺好了,就完了,就万事大吉了,中间缺少某种状态的情况展示效果,我们最后直接甩锅给UI小姐姐。经过这么多年的工作,以及对前端的理解,以及对前端的思考,最终确定了,我们前端要做的事情包含有上述的每一个过程。而且在整个过程中,前端需要跟不同的角色,不同的人进行沟通,以能够更好的将用户的需求实现。
如何推进前端工程化建设
在了解了前端工程化都应该包含哪些东西的时候,就需要考虑前端工程化的建设工作。其实整个工程化建设就是整个前端工作流程的规范化的一个建设。当然中间还夹杂着一些技术层面的优化的内容。但是有一点我可以很肯定的说,前端工程化建设绝对不是仅对webpack的学习和使用,只能说,webpack在前端工程化的过程中起着举足轻重的作用。
接下来我们分步来来聊一下前端工程化的每一步都要做哪些工作:
技术选型
在项目的架构中,我们需要选择各种技术栈所对应的技术;在项目的开发中,我们需要选择各种工具库。技术选型是我们必然会碰到的,我们常常面临的不是单个技术的选型,而是对于一个项目所涉及的一整套技术、方案、规范或者产品的选型。我们需要仔细的去权衡各种技术、各种组合的利弊,做出取舍。
技术选型其实在整个项目的发展过程中,有这举足轻重的地位。继续选型的选型直接影响到项目的后期的发展走向,比如说项目的后续的维护成本;后续相关生态链的建设;未来技术人员的数量等等。因此在做技术选型的时候需要谨慎再谨慎。因此我们要从多方面因素进行考虑技术选型:
- 项目因素: 明确现在项目的规模、重要程度。 项目的需求(特别是非功能性需求)也会限制技术的选型
- 团队因素: 考虑团队的因素,也就是人的因素,考虑团队人员的技术组成。 考虑招聘的因素,对于特别小众的技术,可能会因为招不到人而影响到对公司的业务支持。
- 技术因素: 技术特性考虑(易用性、可维护性、可扩展性、性能等)、技术成熟度、社区活跃度、架构匹配和演化等。 github上的star数,可以作为一个重要的参考。
上面列了在选型过程中我们要考虑的因素,那么实际中我们应该怎么去进行技术选型呢?
- 首先明确选型的需求和目的,最好能列出必须要考虑的各种因素以及评判标准。
- 找候选技术和产品。这时范围可以尽量的广一些,搜集尽可能多的候选技术和产品。
- 初步筛选。把一些由于各种限制无法选择或者明显不可能的技术或产品排除,筛选3个左右备选方案。
- 做一些详细的调查和分析。可以列个技术选型分析表(小的不太重要的技术选型不一定要这么麻烦,而重要的技术选型则可能要反复各个步骤多次)
考虑因素 |
选型A |
选型B |
选型C |
项目因素 |
|||
团队因素 |
|||
技术因素 |
那么在选型过程中需要注意些什么的?
- 一定要进行可行性分析,如果不太确定,做个Demo验证一下,如果项目进行到一半,发现原来设想的方案不可选,那会是非常痛苦和浪费时间的事情。
- 不要有思维定式,也不要赶时髦。举个例子,我就想要一个很简单的活动页面,就纯粹的展示页面,你这边告诉我,需要搭建一个构建平台,在引入一堆的库,什么vue,axios等等……结果功能用一天就不用了。看起来很时髦,很不错,但是完全没有必要。
- 随着业务发展,很多架构需要不断升级,所以一定要考虑未来如果替换某项技术,是否会很麻烦。可以选择一些标准技术或产品,或者在应用中部署一个适配层,方便未来适配其他技术,自由插拔。
- 架构应该尽可能统一,一个领域避免引入太多相同功能的技术产品。
对于前端这边的技术选型来说,我们需要做以下的方面的操作:
- 确定我们的项目的架构方案,是走纯粹的静态页面部署呢还是走服务端渲染(SSR);
- 在确定好大体的架构方案的的前提下,我们需要做基础框架的选择,是选择vue、还是react、还是angular呢,这样的选择直接影响到了我们整个团队的未来的技术栈的构建;
- 选择完基础框架后,前端就是选择UI框架,是使用现有的UI框架呢还是,需要我们自己开发一套属于自己的UI框架;
- 接着我们要考虑使用模块化加载处理方,这个包括CSS的加载处理方案和JS的加载处理方案。对于CSS的预处理方案有SCSS,Less等可以进行选择);对于JS的预处理方案我们可以使用ES6+babel的方案还是使用TS的处理方案等等。
- 接着就是一些基础库的选择,比如说工具类库的lodash,ajax请求库axios,时间处理库dayjs,图表组件echarts等等。
做完技术选择之后,说明我们的前端的工程化建设的脚步的第一步已经迈出去了。接下来就是在此基础上进行的我们后续的建设了。
开发规范设计
谈起开发规范,我想想这个是每个程序员头疼的事儿。当我们接手一个人的项目看到乱遭的代码是不是就会瞬间没有看下去的欲望。古人云“无规矩不成方圆”,开发过程中如果没有规范,只能让我们的屎山越堆越高,后期越来越难维护。可见规范的重要性。始皇帝初统六国即“书同文车同轨”,规范意味着标准,是团队的共识,是沟通协作的基础。对于规范的最基本的载体就是文档,我们要根据不同的内容,制定不同的规范文档:
当然对于规范的制定是需要跟团队成员一起进行讨论约定的,以达到组内大家的共识,这样大家才会愿意去执行。既然规范出来了,那就应该大家去遵守,如果规范制定出来之后,大家都不去执行,那么规范也就成了摆设,那制定规范的意义就完全没有了。当然也有些时候我们制定了规范可能由于疏忽等其他方面的原因,而没有遵循规范,那总得有个检查的办法是吧,这个时候,就需要我们要应对规范实现一定的校验规则:
比如说git规范,我们可以通过githook来在提交之前对提交的内容进行校验,以及分支的创建进行校验什么的;再比如我们都知道ESLint吧,其实就是对代码个是的规范的一个校验等等。在规范实施的过程中,我们可以使用一定的技术手段,来对部分的规范进行约束。当然可能也会有人觉得搞那么多的规范,就很影响工作效率,其实不然,所谓的影响开发效率,只是在刚开始接触的时候会有这种感觉,因为不适应,总得需要有一个适应的过程。一旦当你完全适应了这些规范的话,就会觉得真香。只要规范统一了,标准统一了,对后期的代码维护,以及功能开发是有很大的帮助的。
在各种规范中,这里单独将数据规范单独拎出来强调一下,因为数据的规范可能会直接影响我们前端通用组件,以及通用的工具类的封装。举个例子:当我们在封装接口请求工具的时候,对于登录失败的这种数据的通用处理逻辑应该设计,如果后端关于登录失败,返回的错误码没有一个统一的标准,那前端在处理用户非登录的接口请求就没有办法进行一个统一的封装,就没有办法做到统一封装;再比如说,某些组件外观一样,交互逻辑一样,但是后端返回的数据字段名称不一样(曾经我呆过的一家做酒店相关系统的公司,关于酒店有些人用的chain,有些人用的是hotel,就导致很多通用的组件没办法进行统一的封装,或者是封装好了之后,要根据后端的返回的接口数据字段,再重新处理一下数据格式)。
项目的搭建和开发
对于项目的搭建和开发了流程这一步,可以说是整个前端工程化的一个非常关键的内容,毕竟这个跟我们的前端开发是息息相关的。这一个过程的建设也是整个团队开发工作流的重中之重。这一步我们需要做的的内容其实包含很多的:
- 模块化处理方案:模块化处理方案主要包括有css的预处理和js的预处理,以及加载方案。对于css的预处理不管是scss还是less都是能够提高我们前端的开发效率的;而JS的处理方案,可以使用ES6 + babel,还有Flow,或者是TypeScript等方案处理。对于其加载,JS我们常见的有CMD,AMD,CommonJS以及ESModule的加载方案,要根据不同的的浏览器的兼容性,来进行选择。目前大多数的前端项目是基于webpack来进行开发的,虽说还有别的项目,比如说基于ESModule的vite等等。
- 组件化开发:主要就是我们平时项目中的基础组件,包括基础的UI组件(目前我们基本上使用的都是现有的UI框架):如搜索框,对话框,list,树形结构等,这些元素可以说是构成页面的基础,也就是最原子的东西。我门所有的页面就是通过使用这些最原子的内容,来进行一步的拼装而成的。
- 模块化开发:对于很多的前端来说对于模块和组件的概念很容弄。我理解的,其实模块也属于组件的一种,但是模块是具有独立功能的组件。就比如说一个页面的登录模块、用户的基本信息模块等等。
- 通用组件仓库:对于前端也有相对应的包管理工具npm(当然,现在还有别的一些包管理工具,比如说yarn,pnpm等等)。对于一写我们自己开发的,适用于自己公司内部的一些组件或者是一些通用的工具类库,我们也希望有一个自己的托管平台,因此,需要自己搭建自己的npm私服。并且将内部的一些通用组件进行托管。
- 开发工具:这里所说的开发工具不一定指前端的编辑器。因为我么在开发过程中需要创建项目,创建组件,创业接口扥等一系列的东西,因此在三大框架中就应运而生了各自的cli工具,比如说,react使用的是react-create-app,vue的vue-cli,以及angular的angular-cli工具。这些工具为我们的项目创建,构建,格式校验等提供了不小的便利。
- 项目的构建和部署流程:目前我们使用的前端工具cli工具基本上都是支持我们将我们的项目进行打包,当然,这些也仅仅是打包出来的是官方提供的解决方案的内容。都是能够将我们的项目进行打包,但是远远还不满足我们的CI/CD的需求,因此要建立的完整的CI/CD流程就首先需要我们规范我的构建和部署流程,然后在此基础上去进行开发的我们的CI/CD的流程化工具(目前的Jenkins虽说能够做到一部分的CI/CD的工作,但是要想实现符合自己的企业内部的CI/CD的,还是需要自己做一部分的内容的开发)。
- 性能优化方案:前端性能优化的问题是一个经久不衰的问题,在不同的应用场景以及不同的项目中,所出现的应用瓶颈时不一样的。比如说2C的前端项目中,我们可能更加的看重的是用户的首屏加载,用户的摆平时间,以及用户的交互响应时间等等;在2B的项目中坑出现性能的瓶颈问题的场景就更多了,比如说大数据的加载与渲染等等。但是针对于不同的项目来说,这个性能优化方案应该是在项目开发之初就有所预知,然后进行设计方案,这些也将直接影响到整个前端工程化的建设。
- 自动化测试方案:测试是在开发过程中必不可少的。而自动化测试则能够减少人肉测试,提高代码质量等等。前端常见的自动化测试工具有很多,不管选择哪个都不会有太大的问题。
- Code Review:对于开发者而言,每一行代码其实都应该具备起存在的意义。况且人不是机器,是很容犯错的,有些时候我们开发的问题, 是在测试过程中复现不了的,以及我们的代码规范约定的内容,在有些同学开发过程中有些时候没有注意等等。而Code Review恰恰对这些问题提供一个很好的解决方案。面向小黄鸭的变成,其实就是Code Revew的一种变种。
接口数据的mock
在实际的项目开发过程总,我们会经常遇到如下的尴尬场景:
- 前端开发依赖于后端的接口数据,但是后端人员不足,或者是无法到位,或者是接口正在开发中,就会造成应该提供数据的接口未开发完成,前端这边很多的操作又依赖于接口的数据,导致前端这边的开发工作受阻,造成前端处于一个放空的阶段。
- 我们要写前端的项目文档,但是文档中的某些组件的示例是依赖于后端数据的,但是后端的服务未启动或者是其他的原因,接口不能够进行正常的访问;还有部分的功能是一个完整的流程,流程走过了前端数据的的状态就改变了,如果我们还希望走这样流程,就需要从头开始进行构建数据造成不必要的时间的浪费。
- 对于前端开发,如果需要做前端自动化测试,依赖于数据的部分应该怎么去做,自动化测试返回结果不能够判断是后端数据的问题还验证前端的问题的(因为结果是不确定的),而自动化测试的结果一定是确定字后才能够进行的。这样就需要数据的可靠性,可预知性。
基于上述的场景,就需要我们有一套前端的数据的mock环境,用来mock我们的接口数据(当然这些是基于接口的数据格式跟后端伙伴约定好的前提下进行的)。这就有一个要求就是我们能否通过接口的文档直接生成mock的数据的工具。这里推荐一个不错的接口文档工具“YAPI”(https://hellosean1025.github.io/yapi/),这个工具不仅支持接口文档的输出,还能够在在接口文档上面直接进行mock数据,非常方便。如果说这样的工具和自家的工程化工具的结合的不甚好的话,也可以自己进行开发,这里推荐一个叫做的mockjs的工具,用来进行生成mock数据。
项目的打包发布
前端的项目开发完成了,如果不进行打包发布,就是在耍流氓。对于前端的项目的打包发布这件事情其实贯穿在我们项目开发的整个过程中,从最初的开发、联调、再到测试以及最后的上线交付,都包含有打包和发布的过程。打包发布其实是一件重复,枯燥没有技术含量,并且很容易出错的事情。针对于这种情况,程序员就创造了自动化的大包发布工具。当然对于对于前端来说,也同样的存在这样的一个过程。
我们前端项目的打包发布是基于我们整体的前端项目的架构方案进行的,比如说前后端分离架构方案、性能优化方案、静态资源的存放位置、加载方案、以及部署方案都是我们这个阶段要考虑的问题。然后就是我们前端的CI/CD的方案设计,流程规划以及CI/CD的载体选择和功能开发。
后期的项目维护
项目上线了,不代表就万事大吉了。项目存不存在在测试阶段没有测试到的bug或者是场景;项目的是否能够稳定运行,项目在用户端的使用是否流畅等等一系列的问题。面对这样的问题我们应该如何能够发现,以及在用户遇到这样的问题,能不能有一个反馈等等。相对于后端项目来说,前端的监控相对来说是比较困难的,毕竟要将很多的操作放在用户的设备上进行,然后需要将监控收集的数据进行上报,这个过程中,用户端上报过程都可能出现问题,因此这个上报的数据是可能不会很准确。即使这些数据不是很准确,但是也能够客观地反映出一些问题。因此前端的监控是非常有必要的。而且目前个大平台都在推出自己的前端监控平台,可见前端监控对于前端开发来说是有多么的重要。
小结
以上就是我个人对于前端工程化的理解,可能理解的比较片面,但是随着工作时间的不断的增加,以及科技技术的发展,我相信未来的前端行业会面临着更大的挑战,而前端工程化的内容,也将会不断的跟着时代的发展而快速的发展。