# 团队编码规范约束最佳实践
一千个读者,就有一千个哈姆雷特。
一千个程序员,就有一千个代码风格。
- 代码末尾应不应该添加分号?
- 代码缩进用制表符还是空格?
- 代码缩进两个还是四个空格?
有的开发人员喜欢带分号,有的不喜欢带分号。有的喜欢使用空格,有的喜欢使用 Tab。有的喜欢空两个空格,有的喜欢四个空格。
如果你在一个项目中使用两个空格,不加分号并从一而终这些属于个人代码风格。如果你有的文件两个空格,有的文件四个空格,这种始乱终弃的行为被称作个人代码风格混乱。
以上三个问题都不重要。
重要的是一个团队应使用一致的代码风格。
如果说以上三种属于可协商的代码风格,但以下几种就属于几乎强制性不可协商的的代码质量加强了:
- 使用 const/let,而不使用 var
- 在代码中不要使用
eval
不管如何,团队合作中需要统一规范。
ESLint
就是前端工程中用来统一规范的工具。
减小 code review
的负担!
# ESLint 与约束
统一编码规范不仅可以大幅提高代码可读性,甚至会提高代码质量。当我们设计了一套关于编码规范的规则集时,需要工具去辅助检测,这就是 ESLint
。
$ npm install eslint --save-dev
规则集需要统一集中配置,ESLint 会默认读取配置文件 .eslintrc
来解析,而规则集在 rules
中进行配置:
{
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "double"]
}
}
而我们需要做的是设定我们的代码规范,即 rules
项,关于它的文档及最佳实践参考下文:
# 不要重复造轮子: eslint-config
我们需要推到重来,设计属于自己团队的一套编码规范吗?
完全没有必要推倒重来,既耗费人力,又难以做到规则的全部覆盖。
很多优秀的团队,都根据最佳实践设定了特别优秀的编码规范,比如 airbnb
设定了一套约束特别强的规范。
另外也有一些特别简单但却十分实用的规范,如 eslint:recommended
。
我们仅仅需要使用 extend
配置项去继承一些优秀的开源的代码规范,并使用 rules
做一些自己团队的规则补充
当配置 .eslintrc
时,使用 config.extends
将会继承已有的 .eslintrc
配置文件,配置时可省略 eslint-config-
前缀 (与 babel 相似)。
如使用 airbnb-base
,我们将基于 eslint-config-airbnb-base
这份 eslint 配置文件,再补充自己团队的 rules 进行适配。
{
"extends": ["airbnb-base"],
"rules": {
"semi": ["error", "never"]
}
}
如果团队维护多个前端项目,并且使用一套 eslint
,可对 .eslintrc
进行发包,并以 eslint-config-
为前缀进行命名。
# 开发环境,生产环境与警告
开发环境对于开发而言重要的是什么?
是开发体验。
一个良好的编码规范会带来解放强迫症的舒适感,但过于严格的代码风格有时也会使人烦躁。试举两个小例子,有可能是在你写代码时出现过的场景:
- 禁止掉
console.log
,避免在生产环境输出多余的东西。但偏偏在测试环境经常需要调试,但是如果仅仅设为警告的话,警告又会被忽视,失去意义。 - 特别是当设置了规则
no-unused-vars
时。如果仅仅是为了在开发时调试,却因为无法通过 ESlint 规则校验无法方便调试。
这是一个约束与自由的权衡,ESLint 在提供强有力约束时自然会牺牲一些开发上的便利性。中庸,儒家思想讲究中庸,此时可以在权衡下选择一个中庸的方案:
把 ESLint 的所有影响调试的规则校验都设置为 Warn
,那你又问了警告往往不是会被忽略吗?是这样子的,所以需要在 CI 中设置环境变量 CI=true
,如此在 CI 中即使有警告也无法交付。CI 指持续集成,在本篇文章后边也会接着提到,另外,在本系列文章中也会重点讲解 CI,欢迎持续关注。
如在 create-react-app
中的大部分规则都是设置为 Warn
但是,如果你使用了 webpack
,并且结合 eslint-loader
,那解决方案就更加简单了:使用 emitWarning: true
,在测试环境把所有 Error
都当做 Warn
,这样避免了修改 ESLint 规则,webpack
的配置如下
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
enforce: 'pre',
use: [
{
options: {
cache: true,
emitWarning: true,
},
loader: require.resolve('eslint-loader'),
},
]
}
所以有两种权衡开发体验与编程规范的方式:
- 把 ESLint 的 rule 设置为
Warn
,并在持续集成中配置环境变量CI=true
。 - 结合 webpack 与
eslint-loader
,根据当前环境的环境变量配置emitWarning
。
# 第一层约束: IDE
当不符合代码规范的第一时间,我们就要感知到它,及时反馈,快速纠正,比直到最后积攒了一大堆错误要高效很多。
这里以 VS Code
作为示例,它只需要安装一个插件:eslint
,便可以做到智能提示,来看看效果吧:
另外,配合 eslint-loader
,使用浏览器也可以做到实时提示:
# 第二层约束: Git Hooks
团队合作中的编码规范有一点是,虽然自己有可能不舒服,但是不能让别人因为自己的代码而不舒服。
git 自身包含许多 hooks,在 commit
,push
等 git 事件前后触发执行。与 pre-commit hook
结合可以帮助校验 Lint,如果非通过代码规范则不允许提交。
husky (opens new window) 是一个使 git hooks
变得更简单的工具,只需要配置几行 package.json
就可以愉快的开始工作。
以下为 husky4/husky5 的使用方法,在 husky6+ 中需要通过
~/.husky
目录设置 git hooks
// package.json
{
"scripts": {
"lint": "eslint . --cache"
},
"husky": {
"hooks": {
"pre-commit": "npm lint",
}
}
}
或者结合 lint-staged (opens new window) 调用校验规则
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js|{lib,setup,bin,hot,tooling,schemas}/**/*.js|test/*.js|{test,examples}/**/webpack.config.js}": [
"eslint --cache"
],
"*.{ts,json,yml,yaml,md}|examples/*.md": [
"prettier --check"
],
"*.md|{.github,benchmark,bin,examples,hot,lib,schemas,setup,tooling}/**/*.{md,yml,yaml,js,json}": [
"cspell"
]
}
}
不过做前端的都明白,客户端校验是不可信的,通过一条命令即可绕过 git hooks
。
$ git commit -n
# 第三层约束: CI
git hooks
可以绕过,但 CI(持续集成) 是绝对绕不过的,因为它在服务端校验。使用 gitlab CI
做持续集成,配置文件 .gitlab-ci.yaml
如下所示
lint:
stage: lint
only:
- /^feature\/.*$/
script:
- npm lint
# 小结
- 团队中代码规范统一是极有必要的
- 使用成熟的 eslint config,并做细节修改
- 设置部分 eslint rule 为警告,保障开发体验,并且在
pre-commit
与CI
中把警告视为不通过,保证严格的代码规范 - 可以在
IDE (vscode)
,git hooks
,CI
中添加三层规范校验拦截 - 可以使用
husky
与lint-staged
很方便地做关于 lint 的git hooks
git hooks
的规范校验可以通过git commit -n
跳过,需要在 CI 层继续加强校验