chenglong

Apr 03, 2023

使用 ChatGPT 定制团队专属 ESLint 规则集

notion image

本文主要面向前端和 Node.js 研发团队,介绍如何将 CR 经验更高效地转换成 ESLint 规则集,以提升团队研发质量下限。以下是探讨的内容:
  1. 如何写:使用 ChatGPT 生成 ESLint 规则,并通过 snapshot 测试用例快照提升规则的鲁棒性
  1. 如何配:搭建 ESLint 工程(主要以 Monorepo),根据不同应用规则集需求,在 precommit 和 CI 阶段对增量代码做检测
本文演示的代码见:

背景

ESLint 是一个广泛使用的 JavaScript 代码检查工具,可帮助团队确保代码质量和一致性。然而,ESLint 默认的规则集可能并不符合各团队的具体需求,因此,定制化 ESLint 规则集对于团队高效协作研发是较为常见的需求。

痛点

在研发过程中,使用过 ESLint 的团队通常会遇到以下几个痛点问题:
  1. 祖传代码改不动:接手项目代码时,大部分没有配备 ESLint,为了符合规则,修改祖传代码的风险极高!
  1. 无效规则集较多:实践中,有很多规则过于严格(例如 no-throw-literaldot-notation 等)
  1. 规则定制困难:众口难调,每个团队的代码风格都不同,完全按照业界/公司的代码规范会让团队非常痛苦,而编写一个 ESLint 规则需要与 AST 斗智斗勇。
notion image
(按代码规范的代码检测错误数)

效果

以上痛点的解法大概是:
  1. 增量检测:只对当前变更的代码进行 ESLint 检测
  1. 取其精华:在公司代码规范基础上,关闭无效的规则,只开启『一定会出错』的规则
  1. 利用 ChatGPT:生成式 AI 最适合做这类事,99% 的规则都可以由 ChatGPT 生成的
    1. React JSX 中不允许 number 数字类型直接和 &&(逻辑和) 使用
    2. 不允许使用"登陆",建议改成"登录"
    3. 不允许使用 new Date()、Date(),建议使用 dayjs()
    4. "帐号" and "账户"
最终,每个项目都可以定制规则,并按增量执行检测。如果 CI 检测未通过,则会给出修复命令,如下图所示:
notion image
不同目录执行不同规则

如何写?

ChatGPT

最初,直接使用 ChatGPT 在对话中生成规则。后来,发现可以通过固定 prompt,提供『规则描述』、『正确代码示例』和『错误代码示例』三个参数,让 AI 自动生成规则。
notion image
notion image
notion image
Prompt 使用的是(抛砖引玉,大家有更好的 Prompt 可以交流):

手工

ChatGPT 生成的规则也不是银弹,目前发现没法写 TS 相关的规则,所以这部分只能借助 @typescript-eslint/utils 工具来手写 AST。
新建一个规则文件 packages/eslint/rules/{新规则}.js,借助 AST ExplorerTS ESLint 等工具编写规则:

TS 类型判断

这里举一个很有用的规则:React JSX 中不允许 number 数字类型直接和 &&(逻辑和) 使用,经常会出现页面直接渲染了 0,而不是 hello
这个规则需要借助 typescript-eslint 来写, 解析成 TSEsTree AST 抽象语法树,最终的规则代码如下:

如何测?

快照测试用例

ESLint 官方推荐写规则测试用例通过 RuleTester,但是这无疑增加了规则用例的复杂度,同时还需要处理有效和无效代码的格式。
这里以使用者视角,用更简单的快照方式,规则开发者只需要补 goodbadbad-stdout 三个快照即完成测试用例:
执行测试用例:
有了快照用例后,可以让规则自身功能更健壮:

如何配?

这里我们以单仓 Monorepo 为例,配置 ESLint 规则集,多仓配置方式和单仓中的单个目录规则一致。

目录结构图

主要在两部分:
  • 全量 ESLint 规则集 npm 包:这里用packages/eslint ,包名为 @infras/eslint-config-local
  • 应用 apps/,对 ESLint 的需求中一般有三类:
    • 使用默认规则app1
    • 规则定制app2:主要是开启一些规则
    • 关闭/不使用 lintapp3:不再迭代的废弃应用,不希望
(其中紫色部分为 ESLint 配置部分)

ESLint 规则集 npm 本地包

eslint 规则集是经常快速变化的,不建议通过发包形式使用,而是以本地包方式使用
packages/eslint npm 包目录结构如下:

package.json

先看下 package.json,主要是在公司前端代码规范基础上进行定制:
name 包名一定要以

规则集 react.js

再看下 React 应用的全量规则集 react.js(若有其它类型补充对应规则集文件即可,例如vue.jsnode.jselectron.js
其中:
  • 关闭 prettier 代码风格规则,让 eslint 只专注做错误代码校验
  • rulesdir/* 开头的规则属于团队定制(如何写见后文),使用原生 JS 文件(不用编译规则立即生效):
    • rules/text-specification.js:文案校验
    • rules/jsx-no-numeric-and:避免出现 0 && <div /> 展示 0 的问题
    • rules/lodash-import:前端项目优先使用 lodash-es 而非 lodash
这里关掉了不少『公司级代码规范』规则,原则是只使用『能拦截有效错误的规则』

应用中使用

都是在 apps/*/package.json 中添加 eslint 规则集 npm 依赖

使用默认规则

apps/{子应用}里新建 .eslintrc.js

规则开关

apps/{子应用}里新建 .eslintrc.js ,在 rules 里对具体规则进行 开/关、配置:
所有 ESLint 规则都放到 packages/eslint 里面,应用使用时只做规则开/关

完全关闭/不使用 lint

不新建 apps/{子应用}/.eslintrc.js ,这时候会使用根目录下的 .eslintrc.js 规则(即ignorePatterns 忽略所有文件检测):

工程化

为了系统性严格执行 ESLint 规则,这里在两个阶段对增量代码进行 eslint 检测:
  1. Git 提交前:在本地对变更的代码执行 eslint 检测
  1. CI MR 环节:对当前 MR 中的代码做检测(主要防止通过 git commit -n 方式绕过本地检测)

Git 提交(precommit)

这里使用较成熟的 husky + lint-staged,主要改动:
  1. 根目录 package.json
  1. 执行 husky 安装
  1. 配置根目录的 .lintstagedrc.json 需执行的校验命令
这样每次 git commit 时就会执行规则检测:

CI

CI 为了提高 CR 效率,CI 不过 不 CR,其中 CI 配置有一些优化点:
  1. 使用 git diff 将 MR 中变更文件筛选出来做增量检测
  1. Lint CI 单独配置,这样可以更快执行 lint,给开发者更快地反馈(一次 push 大概 1min 内就可以知道校验结果)
完整配置如下:

一些感受

  1. 只有团队定制的 eslint 规则才有较高价值
  1. 99% 的规则应该由 AIGC(人工智能生成内容) 来完成

Copyright © 2024 chenglong

logo