React企业中台实战 - 第三章.规约:代码提交规范的铁三角
React企业中台实战 - 第三章.规约:代码提交规范的铁三角
Prorise第三章. 规约:代码质量与提交规范
在上一章,我们完成了项目的初始化与环境配置。现在,我们将为这座“大厦”建立一套不可动摇的“建筑规范”。一个没有规约的项目,最终会因混乱而坍塌。本章,我们将着手建立项目的“代码质量铁三角”:
- 代码质量 (Biome.js):建立统一、高效的代码格式化与 Lint 检查标准。
- 提交卡控 (Lefthook):在代码提交前,强制自动执行质量检查。
- 提交规范 (Commitlint):确保每一次代码提交记录都清晰、规范、可追溯。
这个体系将成为项目的“质量守门员”,确保任何进入代码库的代码,都符合团队的最高标准。
3.1. 代码质量基石:集成 Biome.js
3.1.1. 技术选型:为何选择 Biome
在集成工具之前,我们必须先阐明决策。ESLint + Prettier 是过去数年的黄金组合,但我们选择 Biome 是基于对 2025 年前端工程化趋势的判断,核心驱动力是 效率 和 简化。
- 性能差异:
ESLint与Prettier基于 JavaScript/TypeScript 构建,在大型项目中,全量检查与格式化可能耗时数十秒。Biome 使用 Rust 编写,其执行速度是前两者组合的 数十倍。这种速度差异在本地提交和 CI/CD 流水线中,能带来显著的体验提升。 - 配置与维护成本:ESLint + Prettier 方案需要维护至少两个独立的配置文件 (
.eslintrc,.prettierrc)、一系列插件 (@typescript-eslint/parser等) 以及解决它们之间规则冲突的工具 (eslint-config-prettier)。配置过程繁琐且容易出错。 - 一体化优势:Biome 是一个 一体化 工具,它集成了 Formatter(格式化器)、Linter(检查器)和 Importer(导入排序器)。由于功能源自同一内核,它们的设计从根源上避免了规则冲突。我们用一个工具、一份配置,就替代了过去需要多个工具协作才能完成的工作。
选择 Biome,是一次明确的工程升级:用一个更现代、更高效的集成工具,替换掉一个需要繁琐配置才能协同工作的传统组合。
3.1.2. 安装并初始化 Biome
首先,我们将 Biome 作为开发依赖项添加到项目中。
1 | pnpm add -D @biomejs/biome |
安装完成后,我们不手动创建配置文件,而是使用 Biome 的官方命令来初始化,这能确保我们获得一个标准的、包含最新 schema 信息的配置文件。
1 | pnpm biome init |
执行后,项目根目录会生成一个 biome.json 文件。这是我们后续所有代码质量规则的配置中心。
3.1.3. 渐进式配置 biome.json
我们不会一次性展示最终配置,而是逐步添加和解释每一个配置块,理解其背后的架构决策。
第一步:定义基础格式化风格 (Formatter)
我们首先定义团队统一的代码格式化风格。现代开发实践和团队协作的舒适度是主要考量。
文件路径: biome.json
1 | { |
lineWidth: 120:在现代宽屏显示器下,Prettier 默认的 80 字符过于狭窄,常导致 TS 类型和 JSX 属性不自然地换行。120 字符是更舒适、可读性更高的标准。indentStyle: "space"与indentWidth: 2:我们选择使用 2 个空格进行缩进。这是社区中最广泛接受的规范,能确保在任何环境下代码的缩进表现都完全一致。
第二步:配置 Linter 基础规则
接下来,我们开启 Linter,并设定规则的取舍。这里的关键在于找到 严格性 与 实用性 的平衡点。
文件路径: biome.json (追加 linter 配置)
1 | { |
rules: { recommended: true }:开启 Biome 推荐的所有规则集。这是我们的“基础安全网”,能捕获大量潜在的编码错误。suspicious: { noExplicitAny: "off" }:这是一个重要的架构妥协。在企业项目中,尤其是在与类型定义不完善的第三方库集成时,any是一个必要的“逃生舱口”。我们的目标是 逐步减少any的使用,而不是在项目初期就“一刀切”导致开发流程卡顿。a11y: { useKeyWithClickEvents: "off" }:这是另一个基于场景的权衡。此规则要求onClick事件必须伴随键盘事件以保证无障碍访问。对于Prorise-Admin这样的企业内部系统,我们经常使用div或span附加onClick来构建自定义交互。为追求内部组件的开发灵活性,我们选择关闭此规则。
第三步:整合 JavaScript/TypeScript 特定配置
我们针对 JS/TS 文件,特别是 JSX 的书写习惯,进行微调。
文件路径: biome.json
1 | { |
quoteStyle: "single":在 JavaScript/TypeScript 代码中,我们统一使用单引号''。jsxQuoteStyle: "double":在 JSX (类 HTML) 的属性中,我们统一使用双引号""。这是 W3C 规范推荐的做法,也符合社区习惯,实现了代码与标记的风格区分。
注意:这里我们将Css关闭了,因为TailwincssV4的@theme注解无法被biome检测到,这在最新版本的pr中有提及过,还未更新,所以我们暂时关闭css的检测
第四步:配置自动导入排序 (Organizer)
这是 Biome 替代 eslint-plugin-simple-import-sort 的核心功能,用于保持代码整洁。
文件路径: biome.json (追加 organizer 配置)
1 | { |
organizer: { enabled: true }:开启此功能后,Biome 将能够自动对import语句进行排序和分组,极大地提升了代码的规范性和可读性。
3.1.4. 解决 Biome 与“自动导入”的冲突(上一章完成)
配置完成后,我们面临一个预期中的问题:Biome 的 Linter 无法识别由 unplugin-auto-import 插件“魔法般”注入的全局 API,这在我们上一章就已经解决过了,但是我们重复一次
在终端中对 src/App.tsx 文件执行一次检查:
1 | pnpm biome check src/App.tsx |
你会立刻看到 Biome 抛出错误:
1 | src/App.tsx:4:19 lint(correctness/noUndeclaredVariables) |
问题根源:Biome 只认通过 import 语句显式导入的变量。它不知道 unplugin-auto-import 在构建时会自动注入 useState。
解决方案:我们需要让 Biome(以及 TypeScript 编译器 tsc)能够识别这些全局注入的 API。unplugin-auto-import 已经为我们生成了 auto-imports.d.ts 类型声明文件,我们只需在 tsconfig.json 中明确地包含它即可。
文件路径: tsconfig.json
1 | { |
通过在 include 数组中加入 auto-imports.d.ts,我们告诉 TypeScript 和 Biome:“请加载这个文件,里面声明了一些全局可用的类型和变量”。
保存 tsconfig.json 后,再次运行检查命令:
1 | pnpm biome check src/App.tsx |
错误消失了! 这标志着我们的代码质量工具链与自动导入插件已成功协同工作。
3.1.5. Biome 常用命令速查
在日常开发中,我们会频繁使用以下 Biome 命令。理解它们的用途和区别,能让我们更高效地维护代码质量。
基础命令
1. 检查文件(仅报告问题,不修改)
1 | # 检查单个文件 |
用途:在 CI/CD 流水线中使用,或在提交前确认代码质量。
2. 自动修复问题
1 | # 修复单个文件 |
用途:在提交前批量修复格式问题和安全的 Lint 错误。
3. 仅格式化(不执行 Lint 检查)
1 | # 格式化单个文件 |
用途:快速格式化代码,不关心 Lint 问题时使用。
4. 仅 Lint 检查(不格式化)
1 | # 只检查 Lint 问题 |
用途:专注于代码质量问题,不改变格式。
进阶命令
5. 在受 Git 影响的文件上运行检查
1 | # 只检查有改动的文件(需要配置 vcs.enabled) |
💡 用途:在大型项目中,只检查你修改过的文件,大幅提升速度。
6. 使用不同的配置文件
1 | # 使用自定义配置文件 |
推荐的 package.json 脚本
为了方便使用,我们可以在 package.json 中添加快捷脚本:
文件路径: package.json
1 | { |
这样,我们就可以使用更简洁的命令:
1 | pnpm lint # 检查 |
3.1.6. VSCode 集成:让代码质量检查无感化
每次手动运行命令来修复代码格式,这在实际开发中是非常低效的。我们需要让编辑器在 保存时自动应用 Biome 规范,真正实现 “零手动操作” 的代码质量保障,首先我们需要按照官方文档的指示下载专属 Cil
第一步:安装 Biome VSCode 插件
在 VSCode 中安装官方插件:
- 打开 VSCode 扩展面板(
Ctrl + Shift + X) - 搜索
Biome - 安装 Biome 插件(发布者:
biomejs)
或者通过命令行安装:
1 | code --install-extension biomejs.biome |
第二步:配置项目级 VSCode 设置
为了确保团队所有成员都使用统一的编辑器配置,我们在项目中创建 .vscode/settings.json 文件。
文件路径: .vscode/settings.json
1 | { |
editor.defaultFormatter:将 Biome 设为默认格式化工具,替代内置的或其他格式化工具(如 Prettier)。editor.formatOnSave:每次保存文件时,自动执行格式化。editor.codeActionsOnSave:quickfix.biome:自动修复可修复的 Lint 问题source.organizeImports.biome:自动整理和排序 import 语句
- 针对特定文件类型的配置:确保所有 JS/TS/React 文件都使用 Biome。
第三步:创建推荐扩展列表(可选)
为了让新加入的团队成员知道需要安装哪些插件,我们创建一个推荐扩展列表。
文件路径: .vscode/extensions.json
1 | { |
这样,当团队成员打开项目时,VSCode 会提示他们安装推荐的插件。
验证配置
- 打开
src/App.tsx - 故意破坏格式(例如删除分号、改变缩进)
- 按
Ctrl + S保存 - 代码应该自动恢复正确的格式!
常见问题
Q: 保存时没有自动格式化?
- 检查是否安装了 Biome 插件
- 按 Shift + Alt + O(快捷键)
- 重启 VSCode 窗口(
Ctrl + Shift + P→Reload Window)
Q: 与其他格式化工具冲突?
- 禁用 Prettier、ESLint 等格式化插件,或在项目设置中明确指定 Biome 优先级
Q: 某些文件不想使用 Biome?
- 在
biome.json中添加files.ignore配置:
1 | { |
阶段性成果:我们成功用 Biome 替换了传统的 ESLint + Prettier 组合,并基于企业级项目的实际需求,渐进式地定义了代码格式化风格与 Linter 规则。最关键的是,我们解决了 Biome Linter 与 unplugin-auto-import 之间的核心冲突,并通过 VSCode 集成实现了 “保存即规范” 的无感化开发体验。从现在开始,代码质量将不再是负担,而是自动化的基础设施。
3.2. 提交卡控:建立自动化的质量防线
在 3.1 节中,我们拥有了强大的 Biome 工具,并推荐配置了 VSCode 插件,实现了保存文件时自动格式化和检查。但这依赖于开发者的“自觉”和“正确的 IDE 配置”。
企业级项目工程化的核心原则之一,就是 将规范制度化、自动化,而不是依赖于人。万一有团队成员忘记安装插件,或者使用了其他编辑器,他依然可以提交格式混乱或存在明显错误的代码,这将导致代码库质量的“破窗效应”。
因此,我们必须建立一道与编辑器无关的、强制性的、自动化的最终防线——Git 提交卡控 (Git Hooks)。
3.2.1. 技术选型:为何选择 Lefthook (而非 Husky)
Git 钩子 允许我们在 git commit 或 git push 等特定 git 操作发生时,自动执行预设的脚本。Husky 是这个领域的传统标准,但我们选择更现代的 Lefthook,这主要基于 性能 和 维护性 的考量。
性能
Husky基于 Node.js,每次执行钩子都需要启动 Node.js 进程,存在轻微的启动延迟。Lefthook则是一个用 Go 语言 编写的独立二进制文件,其启动和执行速度是毫秒级的,几乎没有额外开销。在每天数十次的提交操作中,这种性能差异会累积成更流畅的开发体验。配置与维护性
Husky的配置分散在.husky/目录下的多个 Shell 脚本文件中。Lefthook将 所有 钩子(如pre-commit,commit-msg)的配置都集中在一个 单一 的lefthook.yml文件中,这种中心化的声明式配置,可读性和可维护性远高于脚本式配置。
3.2.2. 安装与初始化 Lefthook
首先,我们将 Lefthook 作为开发依赖项添加到项目中。
1 | pnpm add -D lefthook |
安装完成后,必须执行 Lefthook 的初始化命令,将它“注入”到本地的 Git 配置中。
1 | git init |
lefthook install 做了什么?
这个命令会在你的本地 .git/hooks/ 目录中创建一系列可执行文件(如 pre-commit, commit-msg)。当你执行 git commit 时,Git 会自动调用 .git/hooks/pre-commit 这个钩子脚本,该脚本会启动 lefthook,lefthook 接着读取 lefthook.yml 的配置来执行我们定义的任务。
3.2.3.渐进式配置 lefthook.yml
现在,我们在项目根目录已经存在了 lefthook.yml 文件,他默认是注释的,让我们从最核心的 pre-commit (提交前) 钩子开始配置
第一步:配置 Lint 检查任务
我们的首要目标是确保任何有 Lint 错误的代码都无法被提交。
文件路径: lefthook.yml
1 | pre-commit: |
pre-commit: 定义了在执行git commit命令 之前 需要运行的任务。commands: 该钩子下可以定义多个命令,这里我们定义了第一个命令,名为lint。glob: 指定这个命令只对特定文件类型生效,避免在无关文件(如.md)上运行 Linter。run: 定义了要执行的脚本。{staged_files}是 Lefthook 内置的变量,它非常关键,意味着pnpm biome lint只检查你通过git add命令暂存的文件,而不是全量检查项目,从而保证了钩子执行的极高速度。
第二步:演练 Lint 拦截
我们来实际验证一下这道防线是否生效。
首先,故意在 src/App.tsx 中制造一个 Lint 错误。
1 | // src/App.tsx |
然后,尝试提交这段有问题的代码。
1 | git add . |
Lefthook 将会立即介入,中止提交并抛出 Biome 的错误报告:
1 | RUNNING pre-commit HOOK |
结果:提交被成功拦截。代码库得到了保护。
第三步:增加自动格式化与类型检查
现在我们的防线已经生效,我们来继续完善它,增加自动格式化和最终的类型检查。
文件路径: lefthook.yml
1 | pre-commit: |
parallel: true:这是一个性能优化选项,告诉 Lefthook 同时并行执行下面所有的命令,以最大化利用 CPU 核心,缩短等待时间。format命令:我们在 Lint 检查的同时,增加了一个格式化任务。--write:告诉 Biome 直接修改文件以修复格式问题。stage_fixed: true:这是 Lefthook 的一个“杀手级”特性。如果biome format自动修复了文件的格式,Lefthook 会自动将这些修改重新git add到暂存区。这避免了开发者“修复了但忘了暂存”的常见错误。
check-types命令:我们添加了pnpm tsc --noEmit作为最后的防线。它会进行全量的 TypeScript 类型检查,确保没有类型错误被提交。--noEmit意味着只检查,不生成任何 JS 文件。
第四步:完整工作流演练
现在,我们修复 src/App.tsx 中的 Lint 错误(删除 unusedVar),并故意破坏一处格式(例如,删除几处缩进)。
然后再次提交:
1 | git add . |
你会观察到以下流程:
- Lefthook 并行启动
lint,format,check-types任务。 format任务检测到格式问题,自动修复了src/App.tsx并将其重新暂存。lint和check-types任务均未发现错误,成功通过。- 所有任务都成功后,
git commit命令顺利完成。
打开你的代码,你会发现格式已经被自动修正了。
阶段性成果:我们利用 Lefthook 建立了一套强大的、自动化的三阶段提交前质量防线。从现在起,任何不符合 Biome 格式、Lint 规则或 TypeScript 类型检查的代码,都将被 自动拦截 或 自动修复 在 git commit 阶段,确保了入库代码的最高质量。
3.3. 提交规范:让代码历史成为可读的文档
我们的代码质量已由 pre-commit 钩子严格把关,但“代码质量铁三角”还缺最后一环,也是同样重要的一环:提交信息的质量。高质量的代码,需要有高质量的提交历史来承载。
3.3.1. 问题的根源:混乱的 Commit Message
想象一下,项目上线后出现紧急 Bug,你需要快速回溯定位问题。你打开 Git 历史,看到的却是这样一幅景象:
灾难性的 Git Log:
1 | - fix |
这几乎是无效信息。你无法判断哪次提交引入了新功能,哪次是关键修复,回溯问题如同大海捞针,项目维护成本急剧升高。
3.3.2. 解决方案:约定式提交规范 (Conventional Commits)
为了解决这个问题,社区诞生了“约定式提交(Conventional Commits)”规范。它规定了一条简单但极其强大的提交信息结构。
一个标准的约定式提交信息结构如下:
1 | <type>(<scope>): <subject> |
type (类型): 必需项。用于说明本次提交的类别。我们不会自定义,而是直接采用社区最主流的
Angular规范中的类型:feat: 新功能 (feature)。fix: 修复 Bug。docs: 仅修改了文档。style: 代码格式修改,不影响代码逻辑 (空格、分号等)。refactor: 代码重构,既不是新增功能也不是修复 Bug。perf: 提升性能的修改。test: 增加或修改测试。chore: 构建流程、辅助工具等非业务代码的变动 (例如修改vite.config.ts)。
scope (范围): 可选项。用于说明本次提交影响的范围,例如某个具体模块。如
feat(auth)、fix(header)。subject (主题): 必需项。对本次提交的简短描述,不超过 50 个字符。
规范化提交带来的价值是决定性的:
- 可读性与可维护性:Git Log 本身就成了一份清晰的技术文档。
- 自动化:我们可以基于
type,自动生成CHANGELOG,自动判断版本升级策略。 - 精准追溯:当需要定位 Bug 时,可以快速过滤
fix类型的提交,实现外科手术式的精准定位。
3.3.3. 集成工具链:安装与配置 Commitlint
现在我们理解了规范,接下来就需要一个工具来 强制执行 它。Commitlint 是这个领域的标准工具。
首先,安装 Commitlint 的命令行工具和我们刚刚学习的“约定式提交”规则包。
1 | pnpm add -D @commitlint/cli @commitlint/config-conventional |
然后,在项目根目录创建 commitlint.config.js 文件,声明我们将采用这套规则。
文件路径: commitlint.config.js
1 | export default { |
3.3.4. 激活钩子:连接 Lefthook 与 Commitlint
工具已就绪,但它需要一个“扳机”来在正确的时间点触发。这个扳机就是 Git 的 commit-msg 钩子。我们回到 lefthook.yml 完成最后的连接。
文件路径: lefthook.yml (追加 commit-msg 配置)
1 | # ... (上一节的 pre-commit 配置) |
工作流程解析:当 git commit 时,pre-commit 钩子首先检查代码质量。通过后,Git 将提交信息写入临时文件,此时 commit-msg 钩子被触发,Lefthook 指挥 commitlint 去校验该文件。如果校验失败,整个提交过程将被中止。
3.3.5. 演练与验证
现在,我们的“铁三角”已全部就位。
第一步:代码无误,但提交信息错误
确保代码可以通过 pre-commit 的检查,然后尝试使用一个不规范的提交信息。
1 | git add . |
第二步:观察 commit-msg 钩子拦截
pre-commit 钩子会静默通过,但 commit-msg 钩子将运行并 失败:
1 | │ 🥊 lefthook v1.13.6 hook: commit-msg │ |
结果:提交被 再次中止。commitlint 明确地告诉我们,它没有找到符合规范的 type 和 subject。
第三步:使用规范的提交信息
我们使用正确的格式重新提交。
1 | git commit -m "chore: test commitlint workflow" |
结果:pre-commit 和 commit-msg 钩子均成功通过,提交完成!
3.3.6. 终极自动化:通过 prepare 脚本实现“零配置”协作
为了让新加入的团队成员能够无感地使用这套规范,我们利用 package.json 的 prepare 脚本,实现 Git 钩子的自动安装。
文件路径: package.json
1 | { |
prepare 是 pnpm/npm 的一个标准生命周期脚本,它会在 pnpm install 命令执行 完成之后 自动运行。这意味着,新成员在克隆项目后,只需运行一次 pnpm install,所有 Git 钩子就会被自动配置好,真正实现了“零手动配置”的团队协作体验。
3.4. 版本控制:初始化 Git 仓库并记录成果
至此,我们已经完成了项目工程化配置的“奠基”工作。这是一个完美的节点,我们应该将这个包含了所有规范和配置的“项目基石”状态,永久地记录下来。我们将通过初始化 Git 仓库并完成我们的第一次提交来实现这一点。
第一步:初始化本地仓库
如果你的项目根目录还不是一个 Git 仓库,请执行以下命令:
1 | git init |
这条命令会在项目根目录下创建一个 .git 目录,正式将我们的 Prorise-Admin 项目置于 Git 的版本控制之下。
第二步:暂存所有文件
我们将所有已创建和修改的文件添加到 Git 的暂存区,准备进行第一次提交。
1 | git add . |
第三步:完成首次规范化提交
这是检验我们本章成果的关键时刻!我们的首次提交 必须 遵循 3.3 节学习的“约定式提交”规范。
对于“初始化项目并集成工程化工具”这一行为,最合适的 type 是 chore,因为它属于构建流程和辅助工具的变动。
1 | git commit -m "chore: initialize project and integrate code quality toolchain" |
当你按下回车键后,你将亲眼见证我们构建的自动化体系开始工作:
- Lefthook 启动:Git 的
pre-commit钩子被触发。 - 代码质量检查:
format,lint,check-types任务会并行运行,检查所有暂存文件。由于我们的代码是规范的,它们会顺利通过。 - 提交信息检查:
commit-msg钩子被触发。 - Commitlint 校验:
commitlint会校验我们的提交信息"chore: initialize project..."。因为它完全符合规范,所以也会顺利通过。 - 提交成功:所有检查都通过后,提交最终完成。
现在,我们项目的坚实基础已经被安全地记录在了 Git 历史中。未来的每一章,我们都将在这个基础上,不断地增加新的、符合规范的提交。
3.5. 本章小结
在本章中,我们为 Prorise-Admin 项目锻造了一套坚不可摧的“代码质量铁三角”,将质量保障从“依赖个人自觉”的原始阶段,全面升级到了“自动化、强制性”的工程化阶段。
- 代码质量 (Biome.js):我们用高性能的
Biome统一了代码格式化与 Lint 检查。 - 提交卡控 (Lefthook):我们通过
pre-commit钩子,建立了代码入库前的“质量门禁”,自动执行格式化、Lint 检查和类型检查。 - 提交规范 (Commitlint):我们首先深入学习了 约定式提交 (Conventional Commits) 规范 的核心结构,然后通过
commit-msg钩子集成了Commitlint,强制执行该规范,确保了 Git 历史的清晰性、可读性和可维护性。 - 自动化工作流 (
prepare脚本):我们利用prepare脚本实现了 Git 钩子的自动安装,将所有规范固化到了项目的工作流之中,达成了“零手动配置”的团队协作目标。 - 版本化基石:最后,我们初始化了 Git 仓库,并使用刚刚建立的完整规范,完成了项目的首次提交,为后续开发奠定了安全、可追溯的版本化基石。
从现在开始,Prorise-Admin 已经具备了强大的 自我净化 和 规范约束 能力,为后续大规模、高质量的功能开发铺平了道路。













