前端工程化
作为一个练习时长两年半的前端练习生,个人认为前端目前资料最零散的部分,就是前端项目的工程化。在目前前端基础技术相对固定且成熟的情况下,项目工程化所需的各种知识就更加能够体现出一名前端程序员的项目经验。
工程规范
从 Git 讲起
版本控制系统在软件工程领域中无疑是十分重要的一个部分,而 Git 则是其中最优秀的一个解决方案。不管是在大型项目还是小玩具中,Git 的使用都可以提高开发与协作的效率。
版本控制
版本控制是 Git 的本职工作,其在大型项目中无论是性能还是效果上都表现极佳。通过追踪分支或文件的 commit 历史,可以很方便地回滚版本、处理 bug。
为了方便版本控制,大多数专业团队会要求开发者遵循提交规范,这里以 Angular Commit (中文版)规范为例。以这种规范的格式来撰写 Commit Message,可以大大提高版本控制过程中定位更改的效率,也可以让你的小伙伴一眼看懂你的 Commit 到底干了些啥。
协作开发
Git 独特的分支系统设计给多人协作项目提供了非常好的开发管理方式,每个开发者可以在不同的 branch 上进行开发,各自的工作内容不会互相影响,在完成各个模块的开发后也可以非常方便地 merge 到主分支中。
在一个工程化的项目中,开发一个新功能的简要过程如下:
通过新建分支的形式,将开发新 Feature 的起点固定在某一个版本,可以在功能开发周期内保证基础代码的不变,避免开发过程中经常更新上游代码导致的一些临时 bug 和开发思路中断。
而 Pull Request 则可以为后续 Code Review 提供平台,保证代码质量。
持续集成和部署
一个成熟的前端工程化项目一定具备持续集成和部署的能力,通过版本控制系统与 CI/CD 系统之间的协作,可以自动化完成一系列重复的工作,提高开发效率。
持续集成(CI)
持续集成(CI)是指将多个开发者的代码变更频繁地集成到一个共享的代码仓库中。这个过程通常涉及以下几个步骤:
- 代码提交:开发者将代码更改提交到版本控制系统(如Git)。
- 自动构建:每次提交后,系统会自动构建代码并运行测试,以确保新代码没有引入错误。
- 早期发现问题:通过频繁的集成,团队能够及早发现和解决代码冲突和缺陷,从而避免在后期阶段出现更大的问题。
持续交付与持续部署(CD)
持续交付和持续部署(CD)是CI的延伸,二者有细微差别:
- 持续交付:指的是在完成自动化测试后,代码可以随时部署到生产环境,但实际的部署过程可能仍需要人工干预。这种方式确保了软件始终处于可发布状态,能够快速响应市场需求和用户反馈。
- 持续部署:则是将所有通过测试的代码自动部署到生产环境中,不需要人工干预。这意味着每次代码变更都能迅速推送给最终用户,从而加快了反馈循环和迭代速度。
CI/CD的优势
- 提高效率:通过自动化构建、测试和部署,减少了手动操作,提高了开发团队的工作效率。
- 降低风险:小规模、频繁的更新使得问题更易于识别和修复,从而降低了大规模发布带来的风险。
- 快速反馈:频繁的发布周期让开发团队能够快速获得用户反馈,从而及时调整和优化产品。
工具与实践
在CI/CD的实施过程中,有许多工具可以帮助团队实现自动化流程,例如:
- 持续集成工具:Jenkins、Travis CI、CircleCI等。
- 持续交付/部署工具:Ansible、Puppet、AWS CodeDeploy等。
- 监控工具:Nagios、Zabbix等,用于实时监控应用性能和健康状态。
此外,最常用也最简单的工具其实是 GitHub Actions,这里不过多赘述,以后也许会另写文章。
赏心悦目的代码风格
前端语言的代码风格相较于其他语言比较灵活,每个人都可能有自己的习惯,例如缩进的 Tab 与空格、是否添加尾逗号、单双引号的使用、行末分号的添加……这些不同的代码风格如果不加以统一,会导致代码看起来十分混乱,也不方便后续的维护。这里介绍两个前端最常用的格式化工具:ESLint & Prettier。
ESLint
ESLint 是一个 JS/TS 代码质量检查工具,侧重于检查语法错误以及代码中可能出现的错误。例如 未被导出的成员、 未被使用的导入……
Prettier
Prettier 是一个代码格式化工具,提供了对于多种语言代码的格式化支持,如 .css
、.sass
、.scss
、.jsx
、.tsx
、.vue
等语言的文件。
两个工具侧重点不同,因此在前端项目中常常同时配置这两个工具来更加全面地规范代码风格。
构建工具
前端项目的基础是 HTML、CSS 与 JavaScript,但仅通过这些语言来开发不够高效,也因此我们需要学习如 Vue、React 这样的前端框架,但这些框架都有着自己特殊的代码形式,而构建工具就是将基于这些框架的代码打包编译成 HTML、CSS 和 JavaScript 的程序。
梦开始的 Webpack
Webpack 是目前运用最广泛的前端项目打包工具,其主要工作是解析 js 代码间的依赖关系、将所有依赖的文件打包到最终的产物 js 文件中、将一些不统一的 ES 语法转换统一。
看起来很抽象,那么 Webpack 到底做了些什么事呢?
在一个完整的项目 当中,一般会有各种不同类型的资源文件,比如 .js
、.jsx
、.css
、.sass
等文件,而 Webpack 所做的就是将这些资源文件进行依赖分析,并整合成一个整体,再分块输出成许多 chunk
便于加载。
这个过程核心完成了 内容转换 + 资源合并 两种功能,实现上包含三个阶段:
- 初始化阶段:
- 初始化参数:从配置文件、 配置对象、Shell 参数中读取,与默认配置结合得出最终的参数
- 创建编译器对象:用上一步得到的参数创建
Compiler
对象 - 初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等
- 开始编译:执行
compiler
对象的run
方法 - 确定入口:根据配置中的
entry
找出所有的入口文件,调用compilition.addEntry
将入口文件转换为dependence
对象
- 构建阶段:
- 编译模块(make):根据
entry
对应的dependence
创建module
对象,调用loader
将模块转译为标准 JS 内容,调用 JS 解释器将内容转换为 AST 对象,从中找出该模块依赖的模块,再 递归 本步骤直到所有入口依赖的文件都经过了本步骤的处理 - 完成模块编译:上一步递归处理所有能触达到的模块后,得到了每个模块被翻译后的内容以及它们之间的 依赖关系图
- 编译模块(make):根据
- 生成阶段:
- 输出资源(seal):根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
Chunk
,再把每个Chunk
转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会 - 写入文件系统(emitAssets):在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
- 输出资源(seal):根据入口和模块之间的依赖关系,组装成一个个包含多个模块的
单次构建过程自上而下按顺序执行,下面会展开聊聊细节,在此之前,对上述提及的各类技术名词不太熟悉的同学,可以先看看简介:
Entry
:编译入口,webpack 编译的起点Compiler
:编译管理器,webpack 启动后会创建compiler
对象,该对象一直存活知道结束退出Compilation
:单次编辑过程的管理器,比如watch = true
时,运行过程中只有一个compiler
但每次文件变更触发重新编译时,都会创建一个新的compilation
对象Dependence
:依赖对象,webpack 基于该类型记录模块间依赖关系Module
:webpack 内部所有资源都会以“module”对象形式存在,所有关于资源的操作、转译、合并都是以 “module” 为基本单位进行的Chunk
:编译完成准备输出时,webpack 会将module
按特定的规则组织成一个一个的chunk
,这些chunk
某种程度上跟最终输出一一对应Loader
:资源内容转换器,其实就是实现从内容 A 转换 B 的转换器Plugin
:webpack构建过程中,会在特定的时机广播对应的事件,插件监听这些事件,在特定时间点介入编译过程
下一代的构建工具!
Vite 被誉为下一代构建工具,以打包速度快、热更新速度快深受开发者喜爱。Vite 所做的事和 Webpack 相同,但在构建过程中的优化比 Webpack 更优秀,HMR 速度和 build 速度都比 Webpack 快很多。
另一方面,与 Webpack 相比,Vite 本身提供的功能十分简单,仅仅只是一个打包工具,因此其基础配置比 Webpack 简洁很多,而其它功能则通过各种官方/社区的插件作为补充。