团队协作(二)—— husky + commitlint 集成

898 阅读2分钟

1. 前言

上篇说到使用 ESLint + Prettier 来解决团队协作下的代码质量问题,本篇将继续介绍如何集成 husky 和 commitlint 进一步规范代码检查和信息提交。

本节代码:github.com/Knight174/t…

欢迎加入技术交流群

下面将以 Vue3 项目举例:

1.1 创建项目

在讲解之前,使用 vite 启动一个 Vue 项目:

$ bun create vite my-vue-app --template vue-ts
$ cd my-vue-app
$ bun install
$ bun run dev

⚠️  注意:如果没有 bun,可以使用 npm、yarn 或 pnpm。

1.2 ESLint

之后使用 eslint 初始化:

$ npm init @eslint/config@latest
# or
$ yarn create @eslint/config
# or
$ pnpm create @eslint/config@latest
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · vue
✔ Does your project use TypeScript? · typescript
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:

eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-vue
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · bun

创建完成后,项目根目录下将生成一个配置文件:eslint.config.js。

import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginVue from 'eslint-plugin-vue';

export default [
  { files: ['**/*.{js,mjs,cjs,ts,vue}'] },
  { languageOptions: { globals: globals.browser } },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  ...pluginVue.configs['flat/essential'],
  {
    files: ['**/*.vue'],
    languageOptions: { parserOptions: { parser: tseslint.parser } },
  },
];

⚠️  注意:

  1. ESLint 目前已经升级到 v9,配置方式和之前的版本有较大不同,这里使用它自己提供的 cli 来创建。
  2. 配置完重启一下 IDE。

回到 App.vue 中制造 2 个语法错误,然后能够被检测出来:

制造 2 个语法错误.png

这证明配置没问题,可以检查 TS 和 Vue3 语法。

在 eslint.config.js 中添加 ignores 数组配置来忽略检测的目录:

import globals from 'globals';
import pluginJs from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginVue from 'eslint-plugin-vue';

export default [
  { files: ['**/*.{js,mjs,cjs,ts,vue}'] },
  { languageOptions: { globals: globals.browser } },
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  ...pluginVue.configs['flat/essential'],
  {
    files: ['**/*.vue'],
    languageOptions: { parserOptions: { parser: tseslint.parser } },
  },
+ {
+   ignores: ['node_modules', 'dist'],
+ },
];

配置好 ESLint 后,在 package.json 中的 scripts 添加 lint 脚本命令:

{
  // ...
  "scripts": {
    // ...
    // 对 src 目录进行类型检查和代码语法检查
    "lint": "vue-tsc -b && eslint src"
  }
}

执行 bun run lint 后,可以看到命令行输出了存在代码质量检测结果。

⚠️  注意:vue-tsc 是必需的,否则无法检测 Vue 文件中的 ts 代码类型问题。

1.3 Prettier

通过 Prettier 进行代码美化,在根目录创建配置文件 .prettierrc:

{
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "bracketSpacing": true,
  "bracketSameLine": true,
  "arrowParens": "avoid",
  "endOfLine": "lf"
}

以及 .prettierignore:

node_modules
dist

⚠️  注意:这一步的前置条件是在 IDE 中安装 Prettier 插件或安装为开发依赖。

2. husky

在 husky 的官网有这么一句话:Automatically lint your commit messagescode, and run tests upon committing or pushing.

这意味着我们可以在提交或者推送途中检查提交信息、代码以及运行测试。

2.1 Git Hooks

说到提交代码,就会想到 Git。Git 中有一个叫做 Git Hooks 的东西,也就是在提交代码的某个阶段会触发的钩子,这里我们只要知道其中 2 个:

  1. pre-commit:在提交代码前触发的 hook,一般在此处运行 lint 检查代码。
  2. commit-msg:在提交 message 时(git commit -m '输入提交信息')触发的 hook,一般用来验证提交信息是否符合要求。

现在通过 git init 给当前项目初始化 git 本地仓库。

2.2 husky 初始化

在项目中安装 husky:

$ bun add --dev husky

初始化一下:

$ bunx husky init

此时,根目录中生成了 .husky 目录。

:.husky 目录.png

而且,package.json 的 scripts 下自动添加了新的脚本命令:"prepare": "husky"

⚠️  注意:prepare 指令是 npm scripts 中的特殊指令,它会在执行 npm install 后自动执行以确保 husky 相关内容被正确设置。

2.3 追加 hook - pre-commit

接下来添加 hook,将 husky 和 git hooks 结合起来。

刚刚说到,我们希望在 pre-commit 阶段执行 lint 操作,那就把 bun run lint 脚本命令写进 .husky/pre-commit 文件里:

$ echo "bun run lint" > .husky/pre-commit

可以看到文件内容如下:

bun run lint

现在,当我们依此输入:

$ git add .
$ git commit -m 'init'

命令行显示如下:

提交后执行 lint 检查.png

可以看到在提交代码之前就会触发 pre-commit 钩子执行 lint 检查了。

3. commitlint

而 commit-msg 钩子一般用于提交信息检查,我们这里使用 commitlint 来实现。

3.1 初始化

# 安装
$ bun add -d @commitlint/{cli,config-conventional}

# 写入内容到 commitlint.config.js
$ echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
// commitlint.config.js
export default { extends: ['@commitlint/config-conventional'] };

3.2 追加 hook - commit-msg

现在就可以追加 commit-msg 钩子了,仍然是和 husky 结合起来,执行以下命令:

$ echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

执行完毕后,可以看到 .husky/commit-msg 文件内容如下:

npx --no -- commitlint --edit $1

3.3 提交规则

这样,提交信息的格式:

#scope is optional; multiple scopes are supported (current delimiter options: "/", "\" and ",")
type(scope?): subject
  • type 是某种提交类型
  • scope 表示当前提交代码的作用范围
  • subject 表示这批代码的主题,也就是概括

按照惯例来说,type 有:

  • build: 与构建系统或外部依赖(如打包工具、依赖项、CI/CD 配置等)相关的更改。 示例:更新 webpack 配置,添加新 npm 依赖
  • chore: 杂务性变更,通常与源代码无关,如更新脚手架、工具配置等 示例:修改项目配置文件、更新工具版本。
  • ci: 与持续集成相关的更改,如修改 CI 配置文件、脚本等。 示例:修改 Jenkinsfile,更新 GitHub Actions 工作流程
  • docs: 仅修改文档的更改。 示例:更新 README 文件,添加 API 文档。
  • feat: 增加一个新功能。 示例:实现用户登录功能,添加新 API 接口。
  • fix: 修复一个 bug。 示例:修复页面渲染错误,修复 API 返回的数据格式问题。
  • perf: 提升性能的代码更改。 示例:优化数据库查询,减少页面加载时间。
  • refactor: 代码重构,不涉及 bug 修复或新功能。 示例:重构组件结构,优化函数逻辑。
  • revert: 撤销之前的提交。 示例:恢复被错误合并的代码。
  • style: 代码风格的更改,不影响功能的更改(如空格、格式、缺少的分号等)。 示例:修改代码缩进,调整代码格式。
  • test: 添加或修改测试。 示例:添加单元测试,修复现有测试。

更详细的内容可查阅此处:github.com/conventiona…

3.4 提交信息成功

在配置好 commitlint 相关操作后,我要提交代码了:

$ git add .
$ git commit -m 'build: 配置commitlint'

提交信息验证通过.png

上面就是成功的例子。

3.5 提交信息失败

如果不按照规则来写提交信息就会报错,比如下面这个例子:

$ git commit -m 'msg传给组件HelloWorld'

提交信息验证失败.png

修改提交信息使之符合规则:

$ git commit -m 'feat: msg传给组件HelloWorld'

修改为符合规则的信息格式.png

OK,最后成功提交,执行 git push 就可以推送到远程仓库了!

4. 总结

在最一开始我们简单回顾了 ESLint 和 Prettier 的配置方法,考虑到 Git Hooks 中的 pre-commit 和 commit-msg 这个两个阶段,前者一般用于 lint 代码,后者用于验证提交信息,我们通过 husky 和 commitlint 将这些集成在一起,既可以保证代码质量又能够规范化提交方式。现在可以跟 💩  山和傻瓜同事说再见了!