跳到主要内容位置

前端工程化其二:程度以及调和

做事的程度,反映开发者的经验和哲学

怎么做

书接上回,我们这期来谈一下怎么做的情况,具体就以我个人经验为例,供各位读者图一乐来使用。

一座建筑的类型在一开始就已经决定,无论他是公园、别墅、牌楼、农村小院、公寓;在设计师开始思考怎么做时,就已经决定了。上回我们说到,前端工程化的需求和呼声在这几年随着前端项目的复杂程度而愈演愈烈的;在过去,传统的”后端“程序员认为前端只是切图仔。这一方面是Vue、jQuery等框架带来的便利性影响等因素,另一方面又有”在地化“的历史性因素所在。那么过分的忽视、不尊重、甚至瞧不起前端岗位的情况下,很容易给自己挖坑。

须知,只要不离职,那么挖的坑最后都会成为一个坑;只要一直挖坑,无论是逃到哪一个公司哪一个天涯海角,最后都会找上门

​ 墨菲定律(不是)

选型和起步#

怎么选呢?任何选择都是有成本的,要在两百多种语言中选择一种语言,且又要在该语言中对应的框架又要选择一种,这框架的候选种类可能也有两百多种。

那么,任何的选择,都要基于自生业务情况,自身知识储备情况,自身团队情况出发,我们无法选择一种自身不了解的东西去做。这个项目、业务是什么样的?移动端还是网页?官网站还是后台站?要做哪些功能点?会有图形可视化还是音视频推流等功能?需要考虑到出发点和未来的扩展,才能选择出较好的符合自身情况的技术栈。

开发语言:

  • JavaScript
  • TypeScript
  • PHP
  • Flutter
  • ... 其他

基于团队情况和自身业务情况,常见的前端语言可能是以上的几种类型中选择一种。

JavaScript#

JavaScript 因为其速度快、效率高,在过去的一段时间内垄断了前端语言生态。但他带来了一些问题,也是不得不正视的。例如:在我的工作经历中,滥用各种类型、甚至是一些比较不好的类型比如说NaN,将它作为一个值来使用的情况;满屏的log输出不清理,造成内存泄露;闭包不清理;使用定时器来强行实现异步等。这其中固然存在这门语言历史性的因素,但是也存在因语言特性造成开发者掌握不够的情况(JavaScript 屏蔽了内存等底层实现细节,但是不代表它就没有)。

简而言之,这个技术选型的特点就是快,但同时,它会拉低上下限。他会让“坑货队友”无限制的拉低你的后腿;即便他存在一些上限,比如一些高手玩家能玩的非常的六,它的上限却不会太过于拔高开发者的水平,也就是说,“高手”玩的再好,也就那样,由于没有存在任何编译阶段的约束,“坑货队友”很容易给你埋下地雷;一颗地雷,在没有运行到那个模块时,你甚至都没办法发现他是一个 undefined 。

它没办法一定程度保住工程质量的下限,选择这门语言进行开发时,要注意应用规模,规模大了的时候,人必然会犯错,而保证每个人协调一致都不犯错所需要的成本本身就很高。

TypeScript#

TypeScript 的说法。这门语言本身挺好的,由于它和 C# 语言是同一个总架构师,它的易用性本身就不算太差。并且它的类型系统是图灵完备的,开发者能够针对类型做“体操”;由于提供了编译检测,在机器和制度的规制之下、能够保证一些工程下限。它的问题也有,比如说程度的问题。

比如: Any 类型的滥用、极其复杂的类型体操、开发者对类型系统的认识不足、过度规制类型系统从而导致开发效率下降等问题。有没有上 TypeScript ,同样也需要视情况而定。当我确定这个项目不会低于预期的规模、同时团队的成员具有一定的知识量水平的时候。我会选择这个方案。阴和阳、万物相生相依,当我全部选择 any 类型作为整个项目的唯一类型,又或者,我写的类型系统甚至能拿来做一个报表的时候,这门语言同样也缺失了其中的意义。做到哪个程度 是对以 TypeScript 开发者最大的命题和挑战。

顺带一提,现在的TypeScript + Node 做全栈项目的趋势是越来越火。其中的原因不一定是 Node 就比传统的 Java 等语言牛逼,而是因为隐形的沟通成本,当前后端都使用同一种语言来接通时,它能减少一些鸡同鸭讲的情况。

其他#

PHP 和 Flutter 的情况:准确的说是 PHP 和 Dart 语言 。这两个语言我一并谈一下,简单来说,这两门语言确实也是能写 Web 项目,但是考虑到兼容性处理,团队的情况等因素,将他们作为特定领域的考量是较为稳妥的。在此我不展开细讲。

路径\包管理工具\插件\检测工具\单元测试\CICD#

路径#

有的读者可能会好奇,路径也能算是工程化管理中的一环吗? 其实是的,我作为救火队临时加入一个项目帮忙开发的时候,经常出现路径找不到的情况。前端不像传统的 Spring 等框架,这类框架是 IOC 类型的,路径的分配就反映着他们的架构。前端如何做?路径是以功能模块划分?还是说以业务模块划分?这其中都需要考量。当然,两者都行,只不过千万不要出现混用的情况,每次看到这种情况总是让人难绷。

包管理工具#

包管理工具也是种讲究,但总的来说选择面不会太广,常见的有以下三种:

  • npm
  • pnpm
  • yarn

同样的,尽量不要出现混用的情况,这会让你的依赖比较难追踪,同时会输出很多的 lock 文件。简要谈一下,上述三种只有 pnpm 是对标 Java 的 Maven 包管理工具,它形成的是一种软链;npm 形成的 node_modules 依赖被戏称为比马里亚纳海沟还要深的事物,原因是它把行程的是全量下载,依赖包会有依赖包,而依赖包的依赖包也会有依赖包,类似于这样的道理;yarn yarn的速度比较快,因为它将依赖包的套娃关系给打平了。

总的来说,速度方面 pnpm 、 yarn 等差不多,npm会明显慢一点。考虑到网络、特殊的开发环境等情况,读者使用符合自己情况的方式即可。我的推荐是用 pnpm 或者 yarn。同时,在工程化规范过程中,选用了其中某一部分,就应该通过脚本等方式规避其他的方式,以免造成混乱。

插件#

插件,总的来说算是辅助类的工具,通常是 Babel、SWC、esBuild 等,它们通常与前端构建工具 Vite 、Webpack 等相互配合使用。它们的作用主要是抹平不同标准下 JavaScript 语言的语法差异。换言之,编译代码是它们主要的作用。上述的几种都各有优劣,SWC 是用 Rust 编写的,速度是它的主要优势;现在的项目存量上主要是 Babel ,属于老牌的编译插件;esBuild 是使用 go 语言做的,它的速度同样也很快。

这一类的话,尽量是选新不选旧,因为本身业务开发的话,不太会改动这一块的东西,只要能正确解析代码,快点总比慢点要让人心情舒畅。

检测工具#

这一类常用的是 ESLint、Prettier。如果使用的是 VSCode 作为开发工具,还要针对使用的框架选择对应的格式化工具,比如 Vue 和 React 的差异。

ESLint 这个比较特殊,不少开发者被折磨的死去活来,我认为它是比较需要的,但是要针对自身的情况做一些调整,同时,它和 ts 的配置有交叉重合的地方。同样的,最近新兴崛起的 Oxlint 是对标老牌的 ESLint ,我倒是认为在业务中,检测速度的快慢影响倒是不大。Prettier 作为比较老牌的格式化工具,我认为是比较好用的,但是根据我的工作经验来看,很多人几乎从来都不看一眼 Prettier 给出的语法警告....

单元测试#

单元测试在大型项目中的作用会非常的大。常用的单元测试主要有 Jest 、Vitest。在编写大型项目、组件库、复杂业务 等场景下,没有单元测试的支持基本上一定会影响工程质量。两者对比起来也是老生常谈,Jest更老牌,Vitest速度方面更快。两者只要会一个另一个就会了,心智负担不会太大。

当然,上单元测试的前提首先要会写(废话),其次,是有必要。否则只是徒增烦恼。

CI/CD#

持续集成,也叫工程流水线,常见的是 Jenkins、Drone 等。在二三线城市,一般都是由后端去搭建环境。这里有两种情况,一种是依托于 Github 、Vercel 等具备 Wasm 的厂商来进行构建;还有一种情况就是自己建仓库 。如果有业务需要或者服务器资源许可的话,自建 CI/CD 也是一种选择,在 Jenkins、Drone 等选择一种即可,Drone 占用的服务器资源更少,但是它在内网环境使用可能会面临一些问题(因为它是 golang 生态,内网环境下载镜像会失败,需要额外再搭镜像)。推荐前端程序员也尝试自己做一下 CI/CD 。

结语#

以上是我对前端工程化的一些经验分享。总的来说,工程化带来的好处是帮助人托底;软件开发再怎么“0 1”,实际的操作者、面向的对象终归是人。太重太过的插件反而会束缚开发者的效率,太少甚至完全不做,又容易让开发者放飞自我。重要的是,决定选型,拍板的那个人,必须要对工程化、工具有一定理解,在自身都不清楚为什么要这么做的情况下,很容易给自己挖坑。我给工程化的总结是”以人为中心、工具的组合“

如果这篇文章对你有帮助,请点击右下角的关注,谢谢。