注册
web

ESLint + Husky 如何只扫描发生改动的文件?

背景


最近公司对代码质量抓得很严, 出台了一系列组合拳:



  1. 制定前端编码规范
  2. 在本地使用git提交代码时进行代码质量检查
  3. 在CI/CD流水线上, 用sonarQube设置了一个代码质量达标阈值,不达标的话无法构建部署
  4. 除了运用工具之外,还增加了定期的CodeReview
  5. 单元测试,线上合并代码时用大模型进行CodeReview也在路上...

今天先说说,在本地使用git提交代码时进行代码质量检查如何实现。现在进入主题


Step1 配置ESLint校验规则


在这一步,踩了一个大坑。现在安装ESLint, 安装的都是ESLint v9.x版本,ESLint v9+的配置文件与之前不太一样了。不管是问大模型,还是上网搜,搜出来的ESLint安装配置方式90%以上都是ESLint V8及以下版本的配置方法。按照那种方式配,会吃很多瘪。


能看懂的,简单一点的报错比如说:



  • .eslintignore文件不再被支持,应该在 eslint.config.jseslint.config.ts 配置文件中,使用 ignores 属性来指定哪些文件或目录需要被忽略。
    (node:13688) ESLintIgnoreWarning: The ".eslintignore" file is no longer supported. Switch to using the "ignores" property in "eslint.config.js": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files (Use node --trace-warnings ... to show where the warning was created) Oops! Something went wrong! :( ESLint: 9.25.1)
  • 改成ignores又报错, 对象字面量只能指定已知属性,并且“ignores”不在类型“ESLintConfig”中,被大模型忽悠了一回。在 ESLint 9.x 中,应该使用 ignorePatterns 来指定要忽略的文件或文件夹,而不是 ignores
  • jiti包版本不匹配, 需要升级
    Oops! Something went wrong! :( ESLint: 9.25.1 Error: You are using an outdated version of the 'jiti' library. Please update to the latest version of 'jiti' to ensure compatibility and access to the latest features.
  • 未安装eslint-define-config模块
    Oops! Something went wrong! :( ESLint: 9.25.1 Error: Cannot find module 'eslint-define-config'

不太容易看懂的报错比如说 ESLint 没有找到适用于文件 src/main.ts 的配置规则。0:0 warning File ignored because no matching configuration was supplied , 按照大模型的提示,逐一检查了ESLint 配置文件的路径是否正确,确保 root: true 配置生效; TypeScript 和 Vue 插件及解析器配置是否正确; ignorePatterns 是否误忽略了 src 文件夹; 检查 tsconfig.json 中的 include 配置; 手动检查文件是否被 ESLint 正确解析


pnpm eslint --config ./eslint.config.ts src/main.ts

忙活了一圈,未能解决问题。大模型排查技术工具最新版本的故障问题能力偏弱。无奈只能在网上搜,一篇一篇的看与试错。最终验证通过是方案是采用@eslint/config生成eslint v9版本的配置文件。


pnpm create @eslint/config

做7个选择(每个选项的含义一眼就能看懂)之后,就能妥妥地生成eslint配置文件。
image.png


Step2 配置Husky


这一步比较简单,虽然Husky最新版本的配置方法与先前的版本不一样了。但新版本的配置比老版本的要简单一些。


✅ 1. 安装Husky v9+版本


pnpm add -D husky

✅ 2. Husky v9+版本初始化


npx husky init

这会自动:



  • 创建 .husky/ 目录
  • .husky/下添加 pre-commit hook 示例
  • 在package.json中添加 "prepare": "husky install" 脚本

这一步有个小坑,就是如果npx husky init第一次因为某种原因运行失败,第二次再运行,不会生成.husky目录。解决方法也很简单粗暴,卸载husky重新安装。


✅ 3. 在package.json配置检查指令


{
"scripts": {
"lint": "run-s lint:*",
"lint:eslint": "eslint src/**/*.{ts,tsx,vue} --debug --cache",
"lint:prettier": "prettier --check ./",
"lint:style": "stylelint \"src/**/*.{vue,css,less}\" --fix",
},
}

✅ 4. 修改 .husky/pre-commit hook


# 检查指令
pnpm lint

Step3 配置ESLint增量检测


为什么要配置增量检测呢,原因有两点:



  1. ESLint全量检测执行的很慢,如果不加--debug参数,很长一段时间,看不到任何输出,会让人误以为卡死了
  2. 开发业务功能的时间本来就捉襟见肘,对于已有项目,当期要偿还历史技术债务的话,时间不允许。

那么如何做增量检查呢?最质朴的思路就是利用git能监测暂存区代码变更的能力,然后利用ESlint对变更的文件执行代码质量检查。这里有两处要注意一下,一是检查暂存区变更的文件,要过滤掉删除的文件,只检查新增,修改,重命名,复制的文件。另外,当没有匹配类型的文件时,files=$(git diff --cached --name-only --diff-filter=AMRC | grep -E '\.(ts|tsx|vue)$')会抛出一个exit 1的异常,造成改了(ts|tsx|vue)之外的文件不能正常提交,所以要在后面加一个|| true进行兜底。


#!/bin/bash
# set -e
# set -x
trap 'echo "Error at line $LINENO"; exit 1' ERR

# 注意这里加了 || true
files=$(git diff --cached --name-only --diff-filter=AMRC | grep -E '\.(ts|tsx|vue)$' || true)

if [ -z "$files" ]; then
echo "No changed ts/tsx/vue files to check."
exit 0
fi

echo "Running ESLint on the following files:"
echo "$files"

# 用 xargs -r 只有在有输入时才执行
echo "$files" | xargs -r npx eslint

echo "All files passed ESLint."
exit 0


Step4 测试效果


修改 src 下的某个 main.ts 文件,故意触发代码质量问题,然后提交。



  • 情形1 通过命令行提交,eslint校验未通过,阻断提交,且是增量校验。

git add . && git commit -m "测试"

image.png



  • 情形2 通过UI界面提交,成功阻断提交
    image.png

至此大功告成,结果令人满意,如果你的项目也需要实现这样的功能的话,拿走不谢。


后记


业务背景是这样的:gitlab上有个填写公司的仓库,有个提交代码的仓库,现在要将提交代码的仓库的代码变更记录,添加到填写工时的议题评论列表中,只要按照 feat: 跨项目提交测试 #194(#194是填写工时的议题id)这样的格式填写提交语,就能实现在评论列表添加代码变更链接的效果。


image.png


在.husky目录下添加prepare-commit-msg文件,内容如下:


#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# 仅当手动写 commit message 时执行
if [ "$2" = "merge" ] || [ "$2" = "squash" ]; then
exit 0
fi

file="$1"
msg=$(cat "$file")

# 查找是否包含 #数字 格式的 Issue 编号
issue_number=$(echo "$msg" | grep -Eo '#[0-9]+' | head -n1 | sed 's/#//')

if [ -n "$issue_number" ]; then
# 自定义项目路径
project_path="research-and-development/algorithm/项目名"

# 如果已经包含路径,则不重复添加
echo "$msg" | grep -q "$project_path" && exit 0

echo "" >>"$file"
echo "Related to $project_path#$issue_number" >>"$file"
fi

需要注意的是,你使用的gitlab版本必须大于v15,才支持跨项目议题关联功能


作者:去伪存真
来源:juejin.cn/post/7497800812317147170

0 个评论

要回复文章请先登录注册