前言
在前端项目开发过程中,我们经常会听到代码规范化这个词,即通过多种工具来对代码、Git记录等进行约束,使之达到某种规范。而这些规范工具多种多样,让人眼花缭乱,本文尝试通过一个工具集,来给出一种前端代码规范化的最佳实践。
本文将基于TypeScript
来讲解,工具集中主要包括以下工具:
- eslint:对代码进行风格和规范进行检查,对不符合规范的代码给出提示,同时可以进行一定程度的自动修复
- prettier:自动格式化代码工具,根据
prettier
规范对代码进行修复,拥有比eslint
更加强大的代码规范性修复能力 - husky:Git hooks工具,通过配置一系列钩子,可以在
git
操作的不同阶段执行相应的命令 - lint-staged:在提交代码前进行lint检查时,可以让lint只检查
git
暂存区(staged
)的文件,而不会检查所有文件 - commitzen:可以实现规范的提交说明的
git-cz
工具,提供选择的提交信息类别,快速生成提交说明,如果需要在项目中使用commitizen
生成符合某个规范的提交说明,则需要使用对应的适配器 - commit-lint:校验提交说明是否符合规范。
commitzen
只是一个实现规范提交说明的工具,但可能存在不使用这个工具直接用git
提交的情况,那么就需要对每次提交说明进行检查是否符合规范
除了上面提到的,其他相关工具会在用到的时候再详细说明。
一、eslint & prettier
1. 首先安装eslint
和prettier
及相关工具
npm install --save-dev eslint prettier
npm install --save-dev eslint-plugin-prettier eslint-config-prettier
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
npm install --save-dev eslint-plugin-import
npm install --save-dev eslint-import-resolver-typescript
其中除了eslint
和prettier
外的其他几个工具作用分别是:
eslint-plugin-prettier
:将 prettier 的能力集成到 eslint 中, 按照 prettier 的规则检查代码规范性,并进行修复eslint-config-prettier
:让所有可能会与 prettier 规则存在冲突的 eslint rule 失效,并使用 prettier 的规则进行代码检查@typescript-eslint/parser
: 解析器,使 eslint 可以解析 ts 语法@typescript-eslint/eslint-plugin
:指定了 ts 代码规范的 plugineslint-plugin-import
:对 ES6+ 的导入/导出语法进行 lint, 并防止文件路径和导入名称拼写错误的问题eslint-import-resolver-typescript
:这个插件为eslint-plugin-import
添加了 ts 支持,详见此处
2. 配置.eslintrc.js
(或者.eslingtrc
,.eslintrc.json
)
module.exports = {
env: {
browser: true,
node: true,
es6: true,
},
parser: '@typescript-eslint/parser', // 解析器
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], // 使用 eslint 和 typescript-eslint 建议的规则
plugins: ['@typescript-eslint', 'prettier', 'import'], // 代码规范插件
rules: {
'prettier/prettier': 'error', // 不符合 prettier 规则的代码,要进行错误提示
},
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx'],
},
'import/resolver': {
typescript: {
project: 'tsconfig.json',
},
},
},
};
配置.prettierrc.js
(或者.prettierrc
,.prettierrc.json
),常用规则如下:
module.exports = {
trailingComma: 'es5',
singleQuote: true,
semi: true,
tabWidth: 2,
printWidth: 80,
};
如果需要还可以加上相应的.eslintignore
和.prettierignore
来忽略想要的目录/文件。
3. 向package.json
的scripts
中添加命令
{
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx ./ --fix"
}
}
现在可以尝试一下编辑任意js
或ts
文件并保存,通过npm run lint
命令来对项目进行 lint 检查,查看是否符合规则的预期,如果安装了 ESLint VSCode 插件(强烈建议安装),还可以实时看到报错提醒。通过npm run lint:fix
命令可以对不符合风格规范的代码进行自动修复。
如果需要对另外一些语法进行 lint 检查,只需添加对应的工具即可,如需要对react
和react hooks
进行检查,则安装eslint-plugin-react
和eslint-plugin-react-hooks
即可
npm install --save-dev eslint-plugin-react eslint-plugin-react-hooks
4. 安装 VS Code 插件
强烈建议安装VS Code插件:Eslint 和 Prettier – Code formatter,通过这两个插件可以实现实时查看当前的eslint和prettier报错而不需要执行命名行检查。
顺便聊一下关于 eslint 和 prettier 的区别
- eslint侧重影响代码质量的问题(比如
==
和===
) - prettier更侧重代码风格的问题(比如代码折行),以及对代码自动修复
eslint很多地方只能warning警告或者报错,但是不能自动修复,比如下面的例子:
-
对于
==
和===
的eslint问题
这个是eslint报的一个问题,点击“快速修复”,只能弹出几个选项,比如disable这个规则,或者展示文档,没有版本自动修复(下面的copilot不算,这个是GitHub Copilot插件AI修复,不属于自动修复) -
对于prettier的代码风格问题
对于这个代码风格问题,点击“快速修复”,提供了几个自动修复的选项(Fix this …/Fix all …)
二、husky
通过上面的步骤,我们已经成功安装并配置了 eslint 相关的检查,但是我们不能仅仅依靠开发人员的自觉来保证提交到仓库的代码符合eslint
规范,这时候就需要husky
这样一个工具来操作git
提供的一些钩子hooks
,在提交代码时对代码进行 lint 检查。
1. 首先是安装husky
npm install --save-dev husky
2. 向package.json
的scripts
中添加命令
{
"scripts": {
"prepare": "husky install"
}
}
prepare
命令会在执行npm install
(不带参数的情况下)之后自动执行。也就是说当我们执行npm install
安装完项目依赖后会执行husky install
命令,该命令会创建.husky/
并指定该目录为git hooks所在的目录。这里我们先手动执行一次npm run prepare
。
3. 配置husky
添加pre-commit
hooks:
npx husky add .husky/pre-commit // 或 npx husky set .husky/pre-commit
这将在./husky/
目录下生成一个pre-commit
脚本文件,在文件里添加npm run lint
这个命令,添加完成后文件内容为:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint
通过上面三个步骤,我们在执行git commit
或者通过git-cz
工具提交时,将会先执行pre-commit
脚本的内容,即执行npm run lint
检查,对不符合代码规范的提交进行阻止,防止污染代码仓库。
4. 注意
上面配置husky
的方式是针对 v5.0+ 的配置方式,针对 v5.0 之前的配置方式,则是在安装husky
之后在package.json
中添加如下配置:
{
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
}
}
这么改的原因是在husky
5.0版本中,做了破坏性的变更,导致两种配置方式不兼容,详见此处。本文推荐使用最新的配置方式。
三、lint-staged
完成husky
配置之后,我们做到了通过每次git提交时都对项目做 lint 检查,防止不符合规范的代码提交到仓库,但是这带来一个问题:每次提交都将对整个项目做 lint 检查,对于一个越来越大的项目来说,这无疑是一个很耗时的操作,除此之外,对于新接入这些配置的项目,项目中可能已经存在了大量不符合规范的代码,不能要求在提交时把所有历史遗留的问题修复之后才能提交。
这个时候就需要用到lint-staged
这个工具了。
1. 安装lint-staged
npm install --save-dev lint-staged
2. 在package.json
中配置lint-staged
在package.json
中添加如下配置,配置表明在运行lint-staged
的时候将只匹配src
和test
目录下的ts
和tsx
文件,我们可以根据自己项目的需要修改配置:
{
"lint-staged": {
"src/**/*.{ts,tsx}": [
"eslint"
],
"test/**/*.{ts,tsx}": [
"eslint"
]
}
}
向package.json
的scripts
中添加命令:
{
"scripts": {
"lint-staged": "lint-staged"
}
}
3. 修改.husky/pre-commit
脚本的内容
将.husky/pre-commit
脚本的内容改为npm run lint-staged
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint-staged
通过上面的步骤,就完成了lint-staged
的配置,这个时候再进行 git 提交时,将只检查暂存区(staged
)的文件,不会检查项目所有文件,加快了每次提交 lint 检查的速度,同时也不会被历史遗留问题影响。如下图:
四、commitzen
有了上面的几个配置后,其实已经算是一个比较完善的代码规范配置了,不过还有一些其他的可以去做的事,比如 git 提交记录规范。
在多人协作开发过程中,如果不注意提交记录的规范,那么每个人可能都有自己的提交风格,如“修复了xxx的bug”、“增加了一个按钮,修改了一处文案”、“config配置文件增加了xxx字段”,更有甚者会在对项目文件做了大量变更后只写一个“增加了若干功能”或“修复了若干问题”这种提交信息。
那什么才一个好的提交信息呢,我们以Angular提交信息规范来举例说明。
在 Angular 提交信息规范中,一个好的提交信息的结构应该如下所示:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
整个提交说明包括三部分:header
页眉、body
正文、footer
页脚,在每个部分之间有一个空白行分隔,其中header
部分是每次提交中必须包含的内容。
header
:
对于header
来说,又包括三部分:body
:
本地提交的详细描述,说明代码提交的详细说明footer
:
主要包括本次提交的 BREAKING CHANGE(不兼容变更)和要关闭的 issue
更加详细的内容请参考Angular提交信息规范。
commitzen
就是这样一个工具,它可以提供可以选择的提交信息类别,快速生成符合规范的提交说明。
1. 先安装commitizen
和cz-conventional-changelog
npm install --save-dev commitizen cz-conventional-changelog
我们在前言中提到,如果需要在项目中使用commitizen
生成符合某个规范的提交说明,则需要使用对应的适配器,而cz-conventional-changelog
就是符合AngularJS规范提交说明的commitzen
适配器。
2. 在package.json
中配置commitizen
在package.json
中添加如下配置,配置指明了cz工具commitizen
的适配器路径:
{
"config": {
"commitizen": {
"path": "node_modules/cz-conventional-changelog"
}
}
}
向package.json
的scripts
中添加命令:
{
"scripts": {
"commit": "git-cz"
}
}
这时我们就可以使用npm run commit
来代替git commit
进行提交了:
3. 配置自定义提交信息规范
如果想定制项目的提交信息规范,可以使用cz-customizable
适配器:
npm install --save-dev cz-customizable
然后把package.json
中配置的适配器路径修改为cz-customizable
的路径:
{
"config": {
"commitizen": {
"path": "node_modules/cz-customizable"
}
}
}
之后在根目录下新建一个.cz-config.js
来配置自定义的规范,这里提供一个官方的示例cz-config-EXAMPLE.js,修改里面字段、内容为自己想要的规范即可
4. 生成日志记录
对于使用了commitzen
的项目,还可以配套使用conventional-changelog-cli
来生成开发日志:
npm install --save-dev conventional-changelog-cli
向package.json
的scripts
中添加命令:
{
"scripts": {
"version": "conventional-changelog -p angular -i CHANGELOG.md -s"
}
}
这样执行npm run version
之后就可以看到生成了CHANGELOG.md
日志文件了。
五、commit-lint
在配置了commitizen
之后,我们可以愉快地使用npm run commit
规范化提交代码,但是配置commitizen
并不等于不能使用git commit
或者其他工具提交,还是存在提交不规范记录说明的可能,那么就需要使用commit-lint
来对每次提交信息进行限制。
1. 安装commitlint
和@commitlint/config-conventional
npm install --save-dev commitlint @commitlint/config-conventional
其中@commitlint/config-conventional
是一个符合Angular规范的校验规则集,就像esint
也需要extends
一些规则集一样,commitlint
也需要extends
一些规则集。
2. 在package.json
中配置commitlint
在package.json
中添加如下配置:
{
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
}
}
向package.json
的scripts
中添加命令:
{
"scripts": {
"commitlint": "commitlint --edit $1"
}
}
注意,我们可能在别的地方见到过commitlint
的下面这种写法
{
"scripts": {
"commitlint": "commitlint -E HUSKY_GIT_PARAMS"
}
}
同样的,这也是一种在husky
v5.0 之前的写法,在新版husky
中不在使用。
3. 向husky
中添加commit-msg
hooks
npx husky add .husky/commit-msg // 或 npx husky set .husky/commit-msg
这将在./husky/
目录下生成一个commit-msg
脚本文件,在文件里添加npm run commitlint
这个命令,添加完成后文件内容为:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run commitlint
这时,如果通过git commit
或其他工具在提交时没有按照规范写提交信息,那么本次提交就会被阻止,如下图:
4. 对于自定义提交信息规范的 lint 校验
上面说的@commitlint/config-conventional
是针对Angular规范的校验规则集,对于使用了cz-customizable
的自定义提交信息规范,就需要使用commitlint-config-cz
这个工具来对自定义规范进行校验了:
npm install --save-dev commitlint-config-cz
然后把package.json
中commitlint
的配置改为:
{
"commitlint": {
"extends": [
"cz"
]
}
}
六、总结
通过上面的这些步骤,我们算是完成了前端代码规范化的配置,到目前,我们新增的配置有:
.eslintrc.js
.eslintignore
.prettierrc.js
.prettierignore
.husky
pre-commit
commit-msg
_
husky自动生成的一个文件夹
package.json
下面只列出来新增的配置,对于package.json
已有的字段没有列出
{
"scripts": {
"prepare": "husky install",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx ./ --fix",
"lint-staged": "lint-staged",
"commit": "git-cz",
"commitlint": "commitlint --edit $1",
"version": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"lint-staged": {
"src/**/*.{ts,tsx}": [
"eslint"
],
"test/**/*.{ts,tsx}": [
"eslint"
]
},
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"config": {
"commitizen": {
"path": "node_modules/cz-conventional-changelog"
}
},
"devDependencies": {
"@commitlint/config-conventional": "^12.1.4",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"commitizen": "^4.2.4",
"commitlint": "^12.1.4",
"conventional-changelog-cli": "^2.1.1",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0",
"husky": "^7.0.0",
"lint-staged": "^11.0.0",
"prettier": "^2.3.2"
}
}
配置过程虽然繁琐,但是对于一个项目,特别是多人协作的大型项目来说,是必不可少的一部分。其实担心配置麻烦,导致每一个新项目都需要重新走一遍配置流程,可以考虑使用Yeoman这个脚手架工具,把一个已经完成代码规范化配置的项目作为模板,通过yo
直接一键生成即可,此处是我创建的一个 demo 工程,包含了上述全部配置:github.com/JingzheWu/l…,以供参考。
参考文章和链接
- 快速配置eslint全家桶
- 前端代码规范最佳实践:eslint+prettier+editorconfig+lint-staged
- Husky
- Husky v5 hook installation
- 升级husky5实践
- husky使用总结
- Cz工具集使用介绍 – 规范Git提交说明
- 使用 commitizen 规范 Git 提交说明
- Angular commit message guidelines
- Angular提交信息规范
- conventional-changelog-cli
原文链接:https://juejin.cn/post/7314365567376162853 作者:酥风