当前位置: 首页 > 科技观察

你能定义前端工程吗?_0

时间:2023-03-13 09:12:53 科技观察

作为一名前端工程师,前端工程是一个经常听到的概念,但是虽然经常听到,但是很多人对它的理解还是比较模糊。比如说到前端工程,他就不能说什么是前端工程。给定一个具体的技术,他不能确定它是否属于工程技术的范畴。这是因为他对前端工程没有概念上的理解。那么,在这篇文章中,让我们来定义一下前端工程。什么是前端工程一说到前端工程,最容易想到的就是编译。需要编译很多代码才能在目标环境中运行:高级语法需要用babel编译成低级版本。less和sass需要各自的编译器转换成css代码。TypeScript代码需要通过tsc或babel等编译器转换为JS代码。...前端工程首先要做的就是支持各种代码的编译。最早的前端工程将这些编译过程以任务的形式组织起来,指定使用哪个编译器编译哪些文件,然后输出到哪个目录。任务可以按顺序、串行和并行指定。Gulp就是这样一种工具,称为任务运行器。这类工具可以组织整个编译过程,对不同的文件进行相应的处理,使其在目标环境中运行。但是因为每个任务都是相对独立的,所以很难做一些全局的优化。后来又出现了另一种思路,不是组织任务,而是分析模块之间的依赖关系,从入口模块开始构建依赖图,中间遇到的js、css、图片等都会作为其他依赖.然后用相应的编译器处理依赖图的每个节点。有同学说,这个方法和taskrunner方法有什么区别?不就是用不同的编译器来处理不同的文件吗?一定有区别。现在我们有了模块之间的依赖图,我们可以做一些全局优化:例如,通过分析依赖关系来删除一些未使用的代码,这称为treeshaking。例如,将这些模块拆分成不同的组(chunk),然后生成不同的文件。这样就把经常变化的模块和不经常变化的模块分成不同的chunk,然后生成到不同的文件中。善用缓存,这叫做代码拆分。而且,由于生成的代码是自己控制的,有自己的runtime代码,所以可以配合runtime实现一些功能,比如实现模块的懒加载,也就是代码拆分分离出来的chunk,即在运行时动态加载。这称为捆绑器,通常是webpack。taskrunner和打包工具的区别还是很明显的:taskrunner只是组织不同的编译任务,并不参与具体的代码处理。处理什么文件以及如何处理它们由开发人员指定。打包工具是分析模块依赖关系,形成依赖图。这样,确定处理哪些文件就可以根据这个依赖关系进行优化,比如treeshking、codesplitting,生成的代码会有自己的runtime,可以配合runtime实现lazyload等功能。由于打包工具的明显优势,逐渐取代了taskrunners,成为主流的构建方式。但是打包工具并不完美,因为每次都要构建整个依赖图,分别处理不同的文件,然后生成代码,所以当项目中的模块太多时,会很慢,而且是很常见的大项目,要打包几分钟的东西。有痛点,大家就会想办法解决,所以就有了nobundle的解决方案,也就是没有打包,比如vite。没有打包,就没有依赖分析,那么如何确定处理哪些文件呢?没有基于支持es模块的浏览器实现bundle。浏览器会对es模块做依赖分析,然后加载相应的模块。自然不需要你自己做依赖分析,只需要编译模块即可。所以nobundle工具会启动一个开发服务器,根据请求的模块路径进行编译,然后返回编译后的代码。当然,生产环境还是要打包的,需要用到打包工具来处理。nobundle方案只是解决了打包工具需要在开发环境中构建整个依赖图的慢痛点。我们回过头来综合看一下:构建的核心就是对不同的文件进行不同的编译。最早的taskrunner方案实现了编译过程的组织,但是没有做全局优化,也没有自己的runtime代码。因此,一种基于依赖分析的打包工具应运而生。打包工具可以基于依赖分析实现treeshking、codesplitting等优化,并可以配合运行时代码实现懒加载。但成功也靠分析,失败也靠分析。这太慢了,所以没有捆绑解决方案。有了浏览器对es模块的支持,实现对应模块的编译服务就可以了,但是生产环境还是需要打包。.那我们就来实地看看吧。如果回到gulp时代,我们能不能实现打包工具,不用bundle服务?不一定,因为打包工具的实现是基于模块规范的,早期是不存在的,所以只能简单的组织一下编译过程。更不用说没有bundle需要浏览器支持es模块了,es模块是近几年才有的。因此,无论是taskrunners、打包工具,还是nobundleservices,都是当前环境下最好的解决方案。并不是说被淘汰的就不好。上面我们只讲了构建,那么前端工程等于构建吗?当然不是,还有很多其他方面,比如代码规范和静态分析:JS代码会使用ESLint来禁止一些写法,比如concole和debugger的使用,也可以修复格式问题,比如缩进方式,以及检查一些逻辑错误,比如在if中使用assignment。CSS代码也使用StyleLint来禁用一些书写风格,修复格式问题,并检查一些逻辑错误。ESLint和StyleLint只是部分格式修复,我们也可以使用prettier进行整体格式化。如果我们使用TypeScript,我们可以使用tsc来执行类型检查并发现代码中潜在的类型不匹配错误。静态分析工具和格式化工具不影响构建。他们通常单独运行,以发现代码中的潜在问题并规范代码格式。代码写好后会上传到代码仓库,比如gitlab,代码托管也是工程的一部分。代码上线后,需要构建和部署。我们可以通过jenkins组织构建过程。当gitlab代码有新的推送时,会触发构建,然后将产品部署到服务器上。基于githook的构建和部署过程称为持续集成,持续部署(CI/CD)。这也是前端工程的一部分。好像很多东西都属于前端工程,那么如何定义前端工程呢?我之前谈到了构建、静态分析、格式化、代码托管和CI/CD。不知道大家有没有发现这些工具的共同特点:它们的处理对象都是代码。他们只是把代码当作一个字符串,不管你用的是vue、react还是angular,你用什么状态管理库,动画库等等。因此,前端工程就是一系列处理代码的工具链。它们不运行代码,而是将代码作为字符串处理。编译构建、ci/cd、代码托管、静态分析、格式化等等都是。不知道大家明白没有。看两个例子:我们项目用的是react,公共组件比较多,所以封装了react的组件库。这属于前端工程吗?不属于。前端框架和组件仅在运行时可用。工程不运行代码,只处理代码。因此,组件库属于前端基础设施,但不属于前端工程。我们几个项目之间有很多共同的代码,所以改成了monorepo的形式,即将多个项目的代码保存在一个项目下,使用pnpmworkspace作为monorepo的管理工具,可以自动关联依赖,统一依赖安装、构建、发布等,这属于前端工程吗?属于。Monorepo是一种组织代码的方式,pnpmworkspace是管理monorepo的工具,也是处理代码的工具,不会运行代码,所以也属于前端工程的范畴。我们公司开发了自己的IDE,集成了很多内部工具。这属于前端工程吗?属于。IDE就是围绕代码编辑的场景,构建一系列的工具链。也是处理代码但不运行代码,所以属于前端工程的范畴。通过这些例子,相信大家对什么是前端工程,哪些技术属于前端工程有了更清晰的认识。我们是前端工程师,所以经常聊前端工程。其实其他语言也有工程化,比如java代码,同样需要构造、格式化、静态分析、CI/CD,所以也就有了工程化的概念。其实大公司都会有工程绩效部门。他们做的是工程,但一般是跨语言工程,不局限于前端工程和后端工程。总结前端工程是指围绕代码处理的一系列工具链。他们把代码当成一个字符串,不运行代码,包括编译构建、静态分析、格式化、CI/CD等。我们详细回顾了编译构建的历史,从taskrunners的演变,打包工具,没有捆绑服务,都是特定时代的产物。然后是eslint、stylelint、prettier、tsc等静态分析和格式化的工具。前端工程化的范围可以非常大,可以包括很多工具,比如monorepo、IDE等,因为代码处理,也就是工程化,在不同的场景下有不同的需求。当你对前端工程有了清晰的定义,就很容易明确前端工程要做什么,哪些技术属于前端工程,哪些不属于前端工程。