背景
在日常需求迭代中,代码的规范与质量是编码的重要一环。Eslint 作为规则扫描器,能够对前端代码进行有效管控,避免出现低级错误,对于前端项目或多或少肯定都会看到 eslint 的相关配置。
但目前存在一些老项目, eslint 的配置仅仅停留在了多年前加的一些 eslint 规则上,没有任何其他动作,导致平常开发中有如下痛点:
- 本地不方便开启保存自动格式化,因为对于老页面,如果开启的话会造成大量的无关
diff。 - 提交代码的时候会受到莫名其妙的卡控。
- 过
pr的时候分号、空格、换行各个地方不对齐,逼死强迫症系列。
基于此,前段时间对老项目的 eslint 进行了一次完善,分享一下整个配置和思考的过程。
选取规则
eslint
eslint 规则可以单独一条条配置,也有一些规则的集合比如官方推荐的 eslint:recommended,框架相关的 plugin:vue/recommended,还有公司开源出来的整套规则比如 Airbnb 的 eslint-config-airbnb,腾讯的 eslint-config-alloy。
选取什么规则不是非常重要,大部分规则集也是类似的,此外本地也可以定义相同的规则名对规则集进行覆盖。
以 alloy 的规则为例,按照 eslint-config-alloy 中的文档安装完相应的 node 包以后,在本地根目录中新建 .eslintrc.js 文件引入相应的规则。
1 | module.exports = { |
如上所示,我们可以在 rules 中定义或者覆盖一些规则。
Prettier
Prettier 是一个代码格式化工具,相比于 eslint 中的代码格式规则,它提供了更少的选项,却更加专业。

相比于 eslint, Prettier 主要格式样式相关的,比如有没有分号、空格数、一行最大字符数等等,而 eslint 通过解析出代码的 AST ,可以自动格式化或者检测出一些潜在的问题,比如是否允许使用 console、变量声明但未使用、switch 缺少 defaut 等。
当然 eslint 也可以配置样式相关的规则,但存在一些情况 eslint 无法胜任,因此格式化相关的我们都交给更专业的 Prettier ,安装 Prettier 的 node 包,并且根目录增加配置文件 .prettierrc.js 。
1 | // .prettierrc.js |
编辑器自动修复
这一步我认为是推动 eslint 最重要的一步,大家抗拒项目添加 eslint 一个很大的原因就是本地没有开启实时检查和自动修复,当提交 commit 的时候遇到 eslint 规则卡控就很难受了。
团队内都使用的 VSCode 进行开发,可以安装 Eslint 和 Prettier 插件。


在本地新增 .vscode/settings.json 文件进行插件的配置,并且该文件不忽略 git ,所有人共享。
1 | { |
这个文件是 VSCode 针对当前工程的配置,配置后保存文件的时候插件会自动帮助我们格式化,同时有实时的错误提示。

这里需要注意的一点是,保存的时候会同时进行 prettier 和 eslint 的修复,如果 eslint 也配置了样式相关的规则,此时可能发生冲突,导致自动格式化后会有 eslint 的报错,此时可以将相应的 eslint 规则手动关闭,也可以引入 eslint-config-prettier 这个规则集批量关闭。
commit 卡控
为了保证 eslint 规则的有效,需要在提交 commit 的时候进行检查,如果存在没有修复的 eslint 问题直接终止提交。
直接使用 "husky": "^1.3.1" 和 "lint-staged": "^8.1.5" 两个 node 包,需要注意下版本号,最新的配置有些不同了,下边是该版本下的配置。
1 | "husky": { |
husky 提供了 pre-commit 的钩子,然后 lint-staged 对暂存区代码自动进行格式化,如果出错的话会直接退出。
这样当我们提交 commit 的时候就会运行 eslint 和 prettier 进行代码的格式化。

流水线卡控
虽然上一步对 commit 进行了卡控,但如果 git commit 的时候添加了 -n 参数,卡控检查也就直接跳过了。
如果想彻底的卡控,我们可以在打包流水线上增加一个 lint 的插件进行检查。
这里实现卡控有两种思路:
发布分支和
master做diff,仅仅对diff出的commit进行eslint的检查。但这里可能存在两个问题需要注意:
如果本地合并
master的时候产生了冲突,然后解决冲突会新提交一个commit。 此时diff出来的commit可能会包含其他人的代码,如果之前的代码没有lint,此时就需要自己lint了。如果上线流程是先合并
master,那么上线的时候master已经有了自己的代码,此时上线分支和master就没有任何diff了,所以也就起不到卡控的作用了。卡控分支前
n天的commit。理想情况下,前
n天只包含自己的commit和已经lint过的commit,merge master的commit可以自动过滤掉,因此可以很好的对新加的代码进行卡控。当然还是无法完全避免遇到别人没有
lint过的代码,此时还是需要自己进行修复了。具体逻辑可以参考这个 node 包。
不管是哪种方法,因为是在老项目引入的 lint ,前期如果在流水线加 lint 卡控的话一定会遇到明明不是自己代码,却被 lint 卡控拦截的情况。
我个人看法是流水线 lint 其实不加也可以,如果编辑器自动修复添加了、commit 卡控也添加了,这已经足够了,如果真有人通过 -n 绕过卡控,那肯定是有理由的,也没必要走流水线再卡控。
上线
因为老项目中会有大量的不符合 eslint 规则的代码,因此上线有两种方案。
本地进行全量文件的
eslint --fix后上线:优点:未来开发时原有文件的
lint问题不用关心,开发者只需关注原有error和自己当前的lint问题即可。缺点:由于改动文件数较多,
eslint不可完全信任,贸然上线可能会造成线上问题。仅仅上线
eslint的卡控和保存时自动lint的配置:优点:未改动代码逻辑,不会存在引发线上问题的隐患。
缺点:当开发者修改、保存老文件后,会自动触发
lint修复,从而污染混淆本身的修改,增加后续code review工作负担。
我是偏向于第 2 个方案的,虽然 eslint 自动修复一般不会引起问题,但程序肯定是不能 100% 相信的,如果造成了线上问题反而得不偿失。
如果采用第 2 个方案,后续开发老页面保存的时候一定会出现大面积的自动 lint,我们可以在添加新代码前先保存一下触发 lint 并且提交一个 msg 为 lint auto fix 的 commit 。这样做有两个好处:
- 后续其他人遇到问题代码排查的时候看到
lint fix就知道了这行代码不是你写的,他需要再往前找一个commit的提交人。 - 过
pr的时候我们可以按commit看,第一个lint的commit如果没什么问题可以直接跳过,减轻cr的负担。
总
在业务迭代繁忙的时候,想在老项目中引入 eslint 其实还挺难的,毕竟业务价值很难讲清楚,一个反向逻辑就是现在项目没有 eslint 也运行的好好的,但加入 eslint 有什么收益呢?
另一方面,当有人推动项目 eslint 的规则的时候仅仅添加规则和卡控,其他的步骤不去推动,当越来越多人遇到需要手动修复 eslint 或者因为 eslint 的问题被卡控提交,内心就会不断地增加对 eslint 的抗拒。
在安装相关插件、node 包的时候需要注意下版本号,找到匹配自己包的版本号的配置,不然可能会遇到配置了但不生效的问题。
当有新项目开发的时候,一定要把 eslint 的自动修复、相关配置都搞好,这样开发的时候也舒服,未来也不用再进行 eslint 的治理了。
未来也可以结合平时开发的经验和发生的线上问题,逐步完善 eslint 中的 rules 规则,使得项目代码质量越来越高。