使用 ESlint、lint-staged 半自动提升项目代码质量
最近在项目部署了ESlint
还有一些配套的工具,比如 prettier
husky
lint-staged
,有些心得写出来分享下。
依据本篇可以实现在git commit
之时,重新格式化代码,同时进行代码检查预防一些低级错误。最终期待项目中的开发人员提交到线上的代码符合代码规范、风格统一,看起来像是一个人写的。
实现过程
-> 待提交的代码
-> git add 添加到暂存区
-> 执行 git commit
-> husky注册在git pre-commit的钩子调起 lint-staged
-> lint-staged 取得所有被提交的文件依次执行写好的任务(ESLint 和 Prettier)
-> 如果有错误(没通过ESlint检查)则停止任务,等待下次commit,同时打印错误信息
-> 成功提交
嗯……这个任务链看起来挺长的,但不要怕,也只是需要装的模块有点多罢了。
可以看成两个部分,代码整理部分、pre-commit 函数部分。
husky 注册 git hook
安装
npm i --save-dev husky lint-staged
添加 hook 函数
// package.json
{
...
"scripts": {
...
"precommit": "lint-staged", // git commit 执行这个命令,这个命令在调起 lint-staged
},
"lint-staged": { // lint-staged 配置
"app/**/*.{js,jsx}": [
"prettier --tab-width 4 --write",
"eslint --fix",
"git add"
]
},
...
}
这里 lint-staged 的配置是:在 git 的待提交的文件中,在 app 目录下的所有 .js .jsx 都要执行三条命令。前两条一会儿说,后一条是将处理过的代码重新 add 到 git 中。
粘贴的时候记得删掉注释,我们知道JSON是没有注释的
prettier 格式化代码
prettier 是强大的代码格式化工具,目的是统一团队的代码格式。相对于 ESlint 代码检查能力较弱。
安装
npm i --save-dev --save-exact prettier
然后……就完成了~ 🎉🎉🎉
这里解释下刚才写在 lint-staged 里的命令参数
prettier --tab-width 4 --write
--tab-width 4
:使用4个空格作为缩进 (嗯,我更喜欢2个,不过……我们的代码规范是4个 😷)
如果想用tab作为缩进可以加上--use-tabs
, 这时--tab-width
代表tab数量。
--write
:默认prettier是直接标准输出到终端的,这个配置代表直接改写文件。
关于prettier的还有一些配置参考这里
ESLint
ESLint 相对来说是比较复杂的部分,很多次我都被繁多的规则和海量的报错吓退过,但好在概念很容易理解,在翻看别的开源项目的时候,发现真正要自行配置的规则也不过尔尔。
而ESLint的作用主要是为了检查代码有没有错误,有没有不和代码规范的地方。虽然 ESLint 有 --fix 的选项,可以自动修复一些格式上的问题,但程度并不能和 Prettier 相当。
Prettier的概念更像是无论你怎么写,走到我这里,都会被格式成我这一种样子。而ESLint 只在发现问题的地方进行 fix,这是两者在逻辑上有区别。
配置 ESLint 主要是配置规则,规则从何而来,那当然是人写的。所以我们在很多项目里都能见到类似 .eslintrc.json
等类似的文件,这就是 ESLint 的配置文件。建议是初始化后一点一点修改这个配置文件,不要照抄Airbnb等等类似的规范,不然上来可能就报非常多的错误,一看就头大。
安装:
npm install --save-dev eslint
// 如果项目使用了 React 需要再安一个 babel-eslint
npm install --save-dev eslint babel-eslint
ESLint 也可以全局安装,全局安装后可以方便用 ESLint 直接执行。
ESLint 初始化
ESLint 初始化可以帮助开发者快速生成一个基本的配置框架。
在项目文件夹下执行
node_modules/.bin/eslint --init
// 如果全局安装了 可以直接 eslint --init
这里会给我们三种方式来初始化ESlint
分别是 1. 问问题 2. 使用大厂的 3. 检查现有的代码自动生成
�我们这里直接选第一个,回答一些问题来确定配置。
根据实际情况回答就好了,即使不小心答错也没关系,都在配置文件里随时可以修改。
部分同学可能有疑惑关于line endings
,其实看一下编辑器下面,如果是 LF 选择 Windows,CR 就选 Linux 就好了 。这个关于windows和linux对换行符的定义不同导致的,有兴趣的同学可以自己搜搜。
生成的.eslintrc.json 根据选择的回答不同,大体都长这样
{
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"windows"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
}
ESLint 配置解释:
env
: Environments,指定代码的运行环境。不同的运行环境,全局变量不一样,指明运行环境这样ESLint就能识别特定的全局变量。同时也会开启对应环境的语法支持,例如:es6。
parser
:ESLint 默认使用Espree作为其解析器,但它并不能很好的适应 React 环境,所以刚才安装了 babel-eslint 用来代替默认的解析器,在配置里这么写"parser": "babel-eslint"
。
plugins
:顾名思义就是插件,插件是单独的npm包,命名一般以eslint-plugin
开头,写的时候用字符串数组的形式,可以省略eslint-plugin
开头。plugins一般包含一个或多个规则配置,可以在extends中引入。
extends
:ESLint 不需要自行定义大量的规则,因为很多规则已被分组作为一个规则配置。
例如:eslint:recommended
就是 ESLint 的推荐规则配置,包含了ESLint的规则 里前面有✔︎的部分,recommended 规则只在ESLint升级大版本的才有可能改变。
相对的 eslint:all
是应用所有的规则,但并不推荐这么做。另外,all 规则是根据版本随时变化的。
extends 还可以以字符串数组的形式定义。
"extends": ["eslint:recommended", "plugin:react/recommended"],
plugin:react/recommended
即为 eslint-plugin-react 插件中的提供的推荐规则配置。
另外还有一点,extends定义的规则如果有重复的,后面的规则会覆盖前面的。
rules
:这里可以对规则进行细致的定义了,覆盖之前前面说的extends中定义的规则。例如 indent
就是对缩进的修改。"indent": ["error",4]
前面一项代表错误等级,第二项是具体配置,有些规则有第三项选项,例如 indent 就有 { "SwitchCase": 1 }
,代表对switch语句采取什么样的缩进策略,如果不设默认是0。具体可以定义什么 rules,可以参考这里
错误等级有三级 0
,1
,2
,分别代表off
,warning
,error
。error错误会终止 lint-staged 执行。
globals
:全局变量,如果你的项目用到其他一些自定义的全局变量,"__DEV__": false
这样配置,true
和 false 代表可不可以被修改。
其他可用的配置参考这个
React Native 项目的配置例子
{
"parser": "babel-eslint",
"env": {
"commonjs": true,
"es6": true,
"react-native/react-native": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
],
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react",
"react-native",
],
"rules": {
"no-unused-vars": 1,
"react/prop-types": 1,
"react/display-name": 0,
}
}
~后面跟了一堆是全局变量,没有使用 react-native 的 config 是因为到目前还不适配 ESLint 4版本。~
eslint-plugin-react-native已经更新了,这样配置又简洁了一些。
调试配置
配置肯定是不能拿来就用的,推荐先就只使用 eslint:recommended
版本,如果你的项目 indent 比较特殊,再到 rules 定义 indent 就可以了。
然后先用命令行命令先对代码库里比较典型文件测试一下
node_modules/.bin/eslint app/app.js --fix
加上 --fix
会自动修复一些问题,规则列表里前面有小扳手的是可以自动修复的。
不用担心,一开始肯定特别多。根据报错信息最后的规则名称,搜索搞清楚到底是为什么错,看这个错误对于你的项目库是什么程度,再到rules里去自定义这条规则。
处理好这一步,就完成部署 commit 自动处理代码的流程了。如果代码没有通过 ESLint 检查,就会出现这种通知,停止commit。
Webstorm
Terminal
Webstorm 插件
从前面看出 Webstorm的通知是不太友好的,我们可以用Webstorm的配置,方便更快的找到错误的发生点(但不是必须的)。
内置了ESlint工具
Webstorm 内置了ESlint工具,启动之后可以在编辑的时候就能看到哪里出错需要修复。
选好 Node 环境路径和 ESLint 包路径,勾线Enable就好了,会自动寻找ESLint的配置。
ESlint 路径:~/Documents/{Your Project}/node_modules/eslint
还可以在快捷键设置里给 Fix ESLint Problem 添加一个快捷键,快速进行代码格式化的操作。
个人感觉在检查代码出错的时候比较好用,但在实际写代码的时候我个人还是倾向于不开这个来写,经常看到报错信息,令人心情不好。
External Tools
我更倾向于自己写一个 External Tools ,方便对当前文件执行命令,在提交之前或者提交报错之后跑一遍,有详细的报错清单,找起来也很方便(但没打开ESLint设置看起来更直观)。
下面三项填入
node_modules/.bin/eslint
--fix $FilePathRelativeToProjectRoot$
$ProjectFileDir$
External Tools 可以设置快捷键,也可以通过 Webstorm 的命令面板搜索打开 cmd + shift + a
。