导读
在前两章中,我们已经完成了 ESLint 与 Prettier 的配置,为 Monorepo 项目建立了统一的代码质量和格式规范。但规范真正落地的关键,不只是"有配置",而是要在代码进入仓库之前自动执行检查,避免开发者忘记运行命令或忽略警告。这正是本章要解决的问题。本章我们将集成 Husky 与 lint-staged:Husky 负责在 Git 提交时触发钩子,lint-staged 则只对暂存区的文件执行 ESLint 与 Prettier,确保每一次提交都经过校验。学完本章,你的项目将拥有一个可靠的提交前自动检查机制,为后续持续集成和团队协作打下坚实基础。
第一步:理解 Husky 9 与 lint-staged 的职责
在开始配置之前,先理解两个核心工具各自解决什么问题,以及它们如何配合,这样后续操作会更清晰。
1.1 Git Hooks 与 Husky 9
Git 本身提供了一系列的钩子(hooks),允许你在特定的 Git 事件(如 commit、push、merge)发生前后自动执行自定义脚本。例如,你可以在每次提交前运行测试、检查代码风格,或者校验提交信息。
但原生的 Git hooks 存在一个痛点:它们存放在 .git/hooks 目录下,而该目录不会被 Git 跟踪,导致团队协作时无法共享同一套钩子,每个人都需要手动配置,而且容易遗漏。
Husky 就是为了解决这个问题而生的。它将 Git hooks 的配置纳入项目仓库中(通常放在 .husky/ 目录),这样所有开发者克隆项目后,只需执行一次初始化(或安装依赖时自动完成),就能获得完全一致的钩子行为。Husky 让我们可以用熟悉的 JavaScript/Shell 来编写钩子,并且配置可版本化、可共享。
1.2 lint-staged:只检查暂存文件
虽然我们可以直接让 Husky 的 pre-commit 钩子执行 eslint . 或 prettier --write .,但这会检查整个项目,随着项目变大,运行速度会明显下降,而且可能会因为历史遗留问题(例如某个旧文件不符合规范)导致提交失败。
lint-staged 专门解决这个问题。它接收 Git 暂存区(staged)的文件列表,然后只对这些文件执行指定的命令。这样有几个好处:
- 速度快:只处理本次提交涉及的文件,而不是全仓库扫描。
- 精准:只关心你要提交的内容,不会因为无关文件的旧问题阻塞提交。
- 可组合 :可以对不同类型的文件指定不同的命令(例如对
.ts文件执行eslint --fix,对.json文件执行prettier --write)。
1.3 两者如何配合
整个提交流程可以概括为:
sql
git commit
→ Husky 触发 pre-commit 钩子
→ lint-staged 获取暂存文件列表
→ 根据配置对暂存文件执行 ESLint / Prettier
→ 检查通过 → 继续执行 commit-msg 钩子(如果有)
→ 检查不通过 → 阻止提交并输出错误信息
下面用一张流程图更直观地展示这个过程:
注:如果配置了 commitlint,在
commit-msg阶段还会进一步校验提交信息格式,这部分会在后续步骤中介绍。
第二步:安装依赖
2.1 安装 Husky 9 与 lint-staged
-
操作 :在项目根目录执行以下命令,将
husky和lint-staged安装到根目录devDependencies中。bashpnpm add -D -w husky lint-staged -
作用:
husky:用于管理 Git hooks,让团队可以共享统一的 Git 钩子配置。lint-staged:只对 Git 暂存区的文件执行校验和格式化命令,避免全仓库扫描,提升提交前检查的效率。
-
为什么安装在根目录:
- Git hooks 作用于整个仓库,所有子包共用一套提交流程即可,无需每个子包单独安装。
- 根目录统一管理 lint-staged 配置,避免在多包项目中重复维护,符合 Monorepo 的集中治理原则。
-
注意:
-w参数表示将依赖安装到 workspace 根目录,而不是当前子包。如果省略-w并在子包目录中执行,pnpm 会默认安装到子包中,这是我们不希望的。- 安装完成后,可以执行
pnpm list -D husky lint-staged --depth 0确认是否安装成功。
第三步:初始化 Husky 9 并生成 pre-commit 钩子
3.1 执行初始化命令
-
操作:在项目根目录执行以下命令,生成 Husky 所需的目录和基础文件。
bashpnpm exec husky init -
作用:
-
自动创建
.husky/目录,用于存放 Git hooks 的配置脚本。 -
在
.husky/下生成一个示例文件pre-commit,默认内容通常是npm test或类似占位命令。 -
如果根目录
package.json中尚未定义prepare脚本,该命令会自动添加:json"scripts": { "prepare": "husky" } -
prepare脚本是 npm/pnpm 的生命周期脚本,会在执行pnpm install时自动运行,从而在团队协作中确保每个成员拉取代码后都能正确初始化 Husky 钩子,无需手动操作。
-
-
注意:
- 初始化后,
.husky/pre-commit文件的内容需要手动修改,我们会在第五步完成。 - 如果
pnpm exec husky init命令在你的环境中没有自动添加prepare脚本,请手动在根目录package.json的scripts中加上"prepare": "husky"。
- 初始化后,
第四步:配置 lint-staged
4.1 创建 lint-staged 配置文件
-
操作 :在项目根目录创建
lint-staged.config.js文件。 -
作用:告诉 lint-staged 如何匹配暂存文件,并对不同文件类型执行对应的校验和格式化命令。集中管理全仓库的提交前校验规则。
-
代码块:
javascript// 根目录 lint-staged.config.js export default { // 匹配所有前端代码文件,先执行 ESLint 修复,再执行 Prettier 格式化 "**/*.{js,mjs,cjs,ts,mts,cts,vue}": [ "eslint --fix", "prettier --write" ], // 对 JSON、Markdown、样式等文件只执行 Prettier 格式化 "**/*.{json,md,css,scss,html}": [ "prettier --write" ] }; -
字段解析:
-
第一组
"**/*.{js,mjs,cjs,ts,mts,cts,vue}":使用 glob 通配符递归匹配 Monorepo 中所有子包的相关文件,包括 JavaScript、TypeScript 和 Vue 单文件组件。 -
数组
["eslint --fix", "prettier --write"]表示对这些文件依次执行命令:eslint --fix:自动修复可修复的 ESLint 问题(如缩进、未使用变量等,取决于规则配置)。prettier --write:对修复后的文件进行格式化,确保代码风格统一。
-
第二组
"**/*.{json,md,css,scss,html}":匹配配置类、文档类和样式类文件,只执行prettier --write,避免 ESLint 对非 JS 文件误报。 -
注意 :命令中直接使用
eslint和prettier,因为这两个可执行文件已安装在根目录的node_modules/.bin中,lint-staged 会自动从该目录查找命令,无需加pnpm前缀。
-
-
补充说明:
- 如果希望某些文件只检查不自动修复,可以将命令改为
eslint(不带--fix)。 - lint-staged 支持传入函数动态生成命令,但当前静态配置已满足大部分需求。
- 如果希望某些文件只检查不自动修复,可以将命令改为
第五步:配置 pre-commit 钩子
5.1 为什么 lint-staged 能只处理暂存文件?
lint-staged 的核心原理是:它通过 Git 命令动态获取当前暂存区(staged)的文件列表,然后只对这些文件执行你配置的命令。
具体来说,当你运行 lint-staged 时,它内部大致做了这几件事:
- 执行类似
git diff --cached --name-only --diff-filter=ACMR的命令,得到所有已暂存的文件路径。 - 根据你在配置文件中定义的 glob 规则(比如
**/*.{ts,vue})对这些文件进行过滤。 - 对每一个匹配的文件,按顺序执行配置的命令(如
eslint --fix、prettier --write)。 - 如果所有命令都成功(退出码为 0),则 lint-staged 返回成功;如果有任何一个命令失败,则返回失败并输出错误信息,阻止提交。
为什么不用 eslint .?
eslint . 会对整个项目目录进行全量扫描,随着文件数量增加,运行时间会越来越长。而且如果仓库中存在历史遗留问题(例如某个旧文件不符合规范),即使与本次提交无关,也会导致提交失败。
lint-staged 的好处:
- 只检查即将提交的内容,避免无关文件干扰。
- 大幅提升检查速度,适合频繁提交的开发节奏。
- 可以按文件类型精细控制执行哪些命令。
与 Husky 的关系 :
Husky 负责在 Git 提交的生命周期触发钩子(如 pre-commit),而 lint-staged 负责在钩子内高效地执行具体校验任务。两者配合,就形成了"提交前只检查暂存文件"的闭环。
5.2 修改 .husky/pre-commit 文件
-
操作 :打开项目根目录下的
.husky/pre-commit文件,将默认内容替换为以下命令。shpnpm lint-staged如果文件不存在,可以手动创建,并确保文件具有可执行权限(Linux/macOS 下执行
chmod +x .husky/pre-commit)。 -
作用 :当开发者执行
git commit时,Husky 会触发pre-commit钩子,并运行pnpm lint-staged。此时 lint-staged 会读取根目录的lint-staged.config.js,对暂存文件执行对应的检查与格式化。只有当所有命令成功执行后,Git 才会继续完成提交;否则提交会被阻止。 -
为什么使用
pnpm lint-staged而不是直接lint-staged或npx lint-staged?pnpm lint-staged会优先使用项目内安装的 lint-staged,确保版本一致,避免全局环境干扰。- 在 Monorepo 中,通过根目录的 pnpm 运行,可以正确识别 workspace 依赖和脚本路径。
-
字段解析:
pnpm:使用 pnpm 作为包管理器来执行命令。lint-staged:要执行的脚本名称,对应根目录node_modules/.bin/lint-staged。
-
权限提醒 :如果提交时提示
husky - pre-commit script failed或Permission denied,大概率是.husky/pre-commit文件没有执行权限,执行chmod +x .husky/pre-commit即可修复。
第六步:配置 commitlint
6.1 安装 commitlint 相关依赖
-
操作:在项目根目录执行:
bshpnpm add -D -w @commitlint/cli @commitlint/config-conventional cz-git commitizen -
作用:
@commitlint/cli:提供commitlint命令,用于校验提交信息。@commitlint/config-conventional:提供基于 Angular 提交规范的标准规则集,是社区使用最广泛的约定。cz-git:提供交互式提交体验和动态 scope 支持。commitizen:提供cz命令,作为交互式提交的入口。
-
为什么需要 commitlint?
统一的提交信息格式能让 Git 历史更清晰,便于生成 changelog、定位问题、代码审查以及自动化发布。常见的规范格式为:
texttype(scope): subject例如:
textfeat(admin): 新增员工管理页面 fix(api): 修复登录接口返回错误的问题
6.2 创建 commitlint 配置文件(含 cz-git 交互式提交)
-
操作 :在项目根目录创建
commitlint.config.js文件。 -
代码块:
javascript// docs:https://cz-git.qbb.sh/zh import fs from "node:fs"; import path from "node:path"; import { defineConfig } from "cz-git"; /** * 动态获取 Monorepo 中的子包目录,作为 commitlint 的 scope 选项。 * 会遍历 apps/ 和 packages/ 两个目录,并额外增加 root 选项。 */ function getScopes() { const scopes = []; const root = process.cwd(); const appsDir = path.join(root, "apps"); const packagesDir = path.join(root, "packages"); // 遍历 apps 目录 if (fs.existsSync(appsDir)) { for (const dir of fs.readdirSync(appsDir)) { const fullPath = path.join(appsDir, dir); if (fs.statSync(fullPath).isDirectory()) { scopes.push({ value: `apps/${dir}`, name: `apps/${dir}` }); } } } // 遍历 packages 目录 if (fs.existsSync(packagesDir)) { for (const dir of fs.readdirSync(packagesDir)) { const fullPath = path.join(packagesDir, dir); if (fs.statSync(fullPath).isDirectory()) { scopes.push({ value: `packages/${dir}`, name: `packages/${dir}` }); } } } // 添加根目录选项 scopes.push({ value: "root", name: "root: 根目录" }); return scopes; } export default defineConfig({ ignores: [commit => commit.includes("init")], extends: ["@commitlint/config-conventional"], rules: { "type-enum": [ 2, "always", ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "revert", "chore"], ], }, prompt: { scopes: getScopes(), messages: { type: "选择你要提交的类型: ", scope: "选择一个提交范围(可选): ", customScope: "请输入自定义的提交范围: ", subject: "填写简短精炼的变更描述:\n", body: '填写更加详细的变更描述(可选)。使用 "|" 换行:\n', breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行:\n', footerPrefixesSelect: "选择关联 Issue 前缀(可选): ", customFooterPrefix: "输入自定义 Issue 前缀: ", footer: "列举关联 Issue (可选) 例如: #31, #I3244:\n", confirmCommit: "是否提交或修改 commit ?", }, types: [ { value: "feat", name: "feat: 🚀 新增功能 | A new feature", emoji: "🚀" }, { value: "fix", name: "fix: 🐞 修复缺陷 | A bug fix", emoji: "🐞" }, { value: "docs", name: "docs: 📚 文档更新 | Documentation only changes", emoji: "📚" }, { value: "style", name: "style: 🎨 代码格式 | Changes that do not affect the meaning of the code", emoji: "🎨", }, { value: "refactor", name: "refactor: ♻️ 代码重构 | A code change that neither fixes a bug nor adds a feature", emoji: "♻️", }, { value: "perf", name: "perf: ⚡️ 性能优化 | A code change that improves performance", emoji: "⚡️" }, { value: "test", name: "test: ✅ 测试相关 | Adding missing tests or correcting existing tests", emoji: "✅", }, { value: "build", name: "build: 📦️ 构建相关 | Changes that affect the build system or external dependencies", emoji: "📦️", }, { value: "ci", name: "ci: 🎡 持续集成 | Changes to our CI configuration files and scripts", emoji: "🎡" }, { value: "revert", name: "revert: ⏪️ 回退代码 | Revert to a commit", emoji: "⏪️" }, { value: "chore", name: "chore: 🔨 其他修改 | Other changes that do not modify src or test files", emoji: "🔨", }, ], useEmoji: true, emojiAlign: "center", themeColorCode: "", useAI: false, aiNumber: 1, allowCustomScopes: true, allowEmptyScopes: true, customScopesAlign: "bottom", customScopesAlias: "custom", emptyScopesAlias: "empty", upperCaseSubject: false, markBreakingChangeMode: false, allowBreakingChanges: ["feat", "fix"], breaklineNumber: 100, breaklineChar: "|", skipQuestions: [], issuePrefixes: [{ value: "closed", name: "closed: ISSUES has been processed" }], customIssuePrefixAlign: "top", emptyIssuePrefixAlias: "skip", customIssuePrefixAlias: "custom", allowCustomIssuePrefix: true, allowEmptyIssuePrefix: true, confirmColorize: true, scopeOverrides: undefined, defaultBody: "", defaultIssues: "", defaultScope: "", defaultSubject: "", }, }); -
字段解析:
getScopes():动态读取apps/和packages/目录,自动生成提交范围选项,新增子包后无需手动维护。ignores:包含"init"的提交信息会跳过校验,方便初始化提交。extends:继承官方预设规则集。rules.type-enum:覆盖官方预设,只允许指定的 type 列表。prompt:cz-git 的交互配置,定义了选择提示、type 列表(含 emoji)、scope 动态来源等。
6.3 配置 commitizen 使用 cz-git
-
操作 :在根目录
package.json中添加以下字段:json{ "scripts": { "commit": "cz" }, "config": { "commitizen": { "path": "cz-git" } } } -
作用 :告诉 commitizen 使用
cz-git作为适配器,这样执行pnpm commit时就能进入 cz-git 的交互式提交界面。
第七步:配置 commit-msg 钩子
7.1 创建 commit-msg 钩子文件
-
操作 :在项目根目录的
.husky/目录下创建commit-msg文件,并写入以下内容。shpnpm commitlint --edit "$1"然后赋予该文件可执行权限(Linux/macOS 下执行):
bashchmod +x .husky/commit-msg -
作用 :当开发者执行
git commit时,Husky 会触发commit-msg钩子,此时会运行commitlint命令,校验当前提交信息格式是否符合commitlint.config.js中定义的规范。如果校验失败,提交会被阻止,并输出错误提示。 -
为什么需要这个钩子?
即使我们使用了 cz-git 交互式提交工具,也只能保证通过它生成的提交信息是规范的。但仍有人可能直接使用
git commit -m "..."绕过交互式提交,导致提交信息不规范。commit-msg钩子作为最后一道防线,确保任何方式产生的提交信息都符合团队规范。 -
字段解析:
pnpm commitlint:使用 pnpm 执行commitlint命令。--edit "$1":$1是 Git 钩子传入的参数,指向包含提交信息的临时文件。--edit表示读取该文件内容进行校验,而不是从命令行参数读取。
-
测试方法:
-
尝试提交一条不符合规范的信息(例如直接写
abc):bashgit add . git commit -m "abc"预期:提交被拒绝,终端会输出类似
"subject may not be empty"或"type may not be empty"的错误。 -
使用交互式提交工具生成一条规范信息,或手动输入符合格式的信息(如
feat(apps/hrms-admin): 🚀 新增测试页面),提交应成功通过。
-
-
补充说明:
- 如果之前没有使用
husky init自动生成.husky/commit-msg文件,可以手动创建。文件内容必须与上述一致。 - 在 Windows 系统上,可能需要使用 Git Bash 或其他 Unix 兼容环境来确保钩子脚本正常运行。
- 如果之前没有使用
第八步:测试提交流程
8.1 测试前准备
在开始测试之前,请确认以下内容已完成:
-
☑ 根目录已安装
husky、lint-staged、@commitlint/cli、@commitlint/config-conventional、cz-git、commitizen -
☑ 根目录存在
lint-staged.config.js -
☑ 根目录存在
commitlint.config.js(使用 cz-git 配置) -
☑ 根目录存在
eslint.config.mjs(供 lint-staged 从根目录运行时使用) -
☑
.husky/pre-commit内容为pnpm lint-staged -
☑
.husky/commit-msg内容为pnpm commitlint --edit "$1" -
☑ 两个钩子文件均有执行权限(Linux/macOS 下
chmod +x .husky/pre-commit .husky/commit-msg) -
☑ 至少存在一个子包(例如
apps/hrms-admin)且已安装依赖
8.2 测试代码格式检查(pre-commit 钩子)
场景一:提交包含不符合 ESLint/Prettier 规范的文件
-
修改
apps/hrms-admin/src/App.vue,故意制造一个格式问题,例如在标签内添加多余空格,或声明一个未使用的变量。 -
执行:
bashgit add . git commit -m "test: 测试 pre-commit" -
预期结果:
- Husky 触发
pre-commit钩子。 lint-staged对暂存文件运行 ESLint 和 Prettier。- 如果发现未使用变量,ESLint 会报错并阻止提交。
- 如果只有格式问题,Prettier 会自动修复文件,然后 Git 会提示你文件已被修改,需要重新
git add后再提交。
- Husky 触发
-
处理:
- 如果 ESLint 报错且无法自动修复,手动修复代码后重新提交。
- 如果 Prettier 自动修复了文件,执行
git add .重新暂存,然后再次提交。
场景二:提交完全符合规范的代码
-
确保
App.vue没有任何格式或代码质量问题(或者使用pnpm lint先修复)。 -
执行:
bashgit add . git commit -m "test: 测试 pre-commit 通过" -
预期结果 :
lint-staged运行成功,Git 继续完成提交。
8.3 测试提交信息校验(commit-msg 钩子)
场景一:直接使用 git commit -m 提交不规范信息
-
执行:
bashgit commit --allow-empty -m "随便写" -
预期结果 :Husky 触发
commit-msg钩子,commitlint校验失败,提交被阻止,终端输出类似:text✖ subject may not be empty ✖ type may not be empty
场景二:使用交互式提交工具(cz-git)
-
执行:
bashpnpm commit -
预期结果:
-
终端进入交互式选择流程:
- 选择提交类型(feat、fix 等,带 emoji)
- 选择提交范围(apps/hrms-admin、packages/eslint-config、root 等,由
getScopes()动态生成) - 输入简短描述
- 可选填写详细描述、关联 Issue 等
-
最终生成的提交信息符合规范,如:
textfeat(apps/hrms-admin): 🚀 新增员工管理页面 -
commit-msg钩子校验通过,提交成功。
-
第九步:避坑指南
坑 1:lint-staged 执行时根目录找不到 ESLint 配置文件
现象 :提交时 pre-commit 钩子报错:
text
ESLint couldn't find an eslint.config.(js|mjs|cjs) file.
原因 :lint-staged 在根目录运行 eslint,而 ESLint 9+ 只在当前工作目录查找配置文件,不会自动向下查找子包配置。子包中的 eslint.config.mjs 无法被根目录的 eslint 识别。
解决方案 :在项目根目录创建 eslint.config.mjs,合并共享配置:
javascript
import baseConfig from "@hrms/eslint-config/base-eslint-config";
import tsConfig from "@hrms/eslint-config/typescript-eslint-config";
import vueConfig from "@hrms/eslint-config/vue-eslint-config";
export default [
{
ignores: ["**/dist/**", "**/node_modules/**", "**/.turbo/**"],
},
...baseConfig,
...tsConfig,
...vueConfig,
];
预防:在 Monorepo 中,根目录始终需要一个 ESLint 入口配置文件,供根目录工具(lint-staged、CI/CD)使用。
坑 2:.husky/pre-commit 或 commit-msg 没有执行权限
现象 :提交时提示 husky - script failed 或 Permission denied。
原因:钩子文件没有可执行权限。
解决方案:
bash
chmod +x .husky/pre-commit .husky/commit-msg
预防:初始化 Husky 后立即检查权限,必要时手动赋予执行权限。
坑 3:Husky 8 和 9 的配置差异
现象 :网上很多教程使用 npx husky install 或 husky add 命令,但你的 Husky 9 环境不生效。
原因:Husky 8 和 9 的初始化方式完全不同:
| 版本 | 初始化命令 | 配置位置 | 钩子文件 |
|---|---|---|---|
| Husky 9 | husky init |
.husky/ 目录 + prepare 脚本 |
.husky/pre-commit 等 |
| Husky 8 | husky install |
package.json 的 "husky" 字段 |
手动创建或 husky add |
解决方案:确认 Husky 版本,使用对应的初始化方式。本文基于 Husky 9。
预防 :开始配置前先查看 package.json 中 husky 的版本号。
坑 4:cz-git 的 cz 命令不存在
现象 :执行 pnpm cz 或 git cz 报 Command not found。
原因 :cz-git 本身不提供 cz 命令,需要配合 commitizen 使用。同时需要在 package.json 中配置 config.commitizen.path 指向 cz-git。
解决方案:
-
安装 commitizen:
bashpnpm add -D -w commitizen -
在根目录
package.json中添加:json{ "scripts": { "commit": "cz" }, "config": { "commitizen": { "path": "cz-git" } } } -
使用
pnpm commit启动交互式提交。
预防:cz-git 官方文档中明确说明需要与 commitizen 配合使用。
坑 5:zsh 中 workspace:* 通配符被展开
现象:在 zsh 终端执行:
bash
pnpm add -D -w @hrms/eslint-config@workspace:*
报错 zsh: no matches found。
原因 :zsh 会把 * 当作文件通配符尝试展开。
解决方案:用引号包住参数:
bash
pnpm add -D -w "@hrms/eslint-config@workspace:*"
预防 :在任何包含 * 的命令行参数中,养成加引号的习惯。
第十步:小结
本章我们完成了 Husky 9 + lint-staged + commitlint + cz-git 的完整集成,核心成果包括:
- 根目录安装
husky和lint-staged:统一管理全仓库的 Git hooks 和暂存文件检查。 - 创建
lint-staged.config.js:按文件类型配置 ESLint 和 Prettier 的执行策略。 - 配置
.husky/pre-commit:在提交前自动执行 lint-staged,确保代码质量和格式。 - 根目录创建
eslint.config.mjs:解决 lint-staged 从根目录运行时的配置查找问题。 - 安装并配置 commitlint + cz-git + commitizen:实现提交信息规范校验和交互式提交体验。
- 配置
.husky/commit-msg:在提交信息生成后自动校验格式,防止绕过交互式提交。
最终形成的提交流程:
text
git add .
pnpm commit(或 git commit)
↓
pre-commit 钩子 → lint-staged → ESLint/Prettier 检查暂存文件
↓
commit-msg 钩子 → commitlint 校验提交信息
↓
提交完成 ✅
这套体系让代码规范和提交规范从"手动执行"变为"自动强制",为后续 Turborepo 任务编排和 CI/CD 打下了坚实基础。
写在最后
本章我们通过 Husky 9 与 lint-staged,将代码规范和格式化检查从"手动执行"升级为"提交前自动执行",为 Monorepo 项目建立了一道质量防线。配合前几章的共享 ESLint/Prettier 配置,现在任何子包都能在提交时自动获得一致的代码校验,减少人为疏漏,提升团队协作效率。
更进一步,我们引入了 commitlint 与 cz-git,让提交信息也进入了规范化轨道:交互式提交降低了规范的门槛,commit-msg 钩子则确保任何提交方式都逃不过格式校验。
后续我将继续完善工程化体系,包括引入 Turborepo 任务编排、配置 CI/CD 等,欢迎持续关注。如果本文对你有帮助,欢迎点赞、收藏、评论,也欢迎指出不足之处,一起交流进步。