前端代码规范工具主要是从三个方面提升代码质量(分别对应标题三种工具):
- 提高代码质量,捕获潜在的bug,比如使用未使用的变量声明(no-unused-vars)、避免精度丢失(no-loss-of-precision);
- 统一代码格式,避免百花齐放,比如每行代码最大长度(max-len)、关键字前后空格数(keyword-spacing);
- 阻止不规范代码进入代码库,规范提交信息。
本文会从依据各工具官方文档等分别对其原理和使用进行解读,并给出最佳实践,从而做到知其然知其所以然还有怎么用。
eslint
js是动态且类型宽松的语言,容易产生错误且需要在运行时发现,因此微软推出了另一个语言typescript来弥补js的天生不足(如果要进一步了解ts,可参考按照新的思路再学一遍typescript)。
而怎么能最小化解决这个问题呢?那就是使用linting工具,这里推荐的是eslint,eslint是An AST-based pattern checker for JavaScript
,可以根据js代码生成的抽象语法树静态分析代码是否符合各种自定义的规则,而不需要执行便可以发现错误并自动修复(可同时处理代码质量和代码格式)。
上面一句话基本概括了eslint的特点和工作原理,下面从以下几个方面做一下深入了解:
- 使用方式
- 配置
- vscode集成
使用方式
eslint是一个npm包,要想使用需要先安装,然后通过执行命令行命令来对相关文件进行代码检查和修复,其中涉及到使用过程中的一些配置,可以直接在命令行上添加,也可以通过配置文件配置,这里介绍的使用原则是除了少部分需要在命令行添加的,其他配置参数都在配置文件配置。
下面介绍基本使用方式,Node.js版本要求:^10.12.0, or >=12.0.0。
- 安装(以yarn为例)
yarn add eslint --dev
- 初始化配置文件(如果全局安装可以直接使用npx,否则需要添加npx) eslint运行时会根据相关配置工作。
npx eslint --init
执行该命令后要根据选项自定义一些配置,比如
How would you like to use ESLint? · style
√ What type of modules does your project use? · esm
√ Which framework does your project use? · none
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser, node
√ How would you like to define a style for your project? · guide
√ Which style guide do you want to follow? · standard
√ What format do you want your config file to be in? · JSON
此时在项目根目录生成了一个.eslintrc.json
的配置文件并下载了依赖的安装包。
- 检查并修复
eslint使用语法为eslint [options] [file|dir|glob]*
,比如
eslint file1.js file2.js
eslint lib/**
相关选项包括:
- --fix 修复
- -c, --config 指定另外的配置文件
配置
eslint被设计成完全可配置的,这意味着可以关掉所有规则只留下基本的语法验证,有两种主要的配置方法(不包括在命令行中配置):
- Configuration Comments:直接在文件中使用注释作为配置
- Configuration Files:使用 JavaScript, JSON or YAML文件作为整个目录乃至子目录的配置,整体结构可以参考schema 具体配置参考Configuring ESLint,这里对主要配置做一下介绍
- parserOptions:解析的语言选项,包括ecma版本、代码类型(module或script)、ecma特性(比如jsx等)
- parser:解析器,用来把js解析成AST,默认Esprima,可以使用ts或babel的解析器以兼容
- processor:处理器,可以用来从其他类型文件中提取js进行处理
- env:通过设置相应环境预设全局变量,比如browser或node等
- globals:自定义的全局变量
- plugins:插件是一系列eslint-plugin-为前缀的npm包,使用时可以不带前缀,插件可以自定义规则等,也可以提供配置方便复用
- rules:具体规则,eslint默认的规则见Rules,可以对具体规则进行修改,可选值包括
- "off" or 0 关闭规则
- "warn" or 1 警告
- "error" or 2 报错 多个参数时使用数组语法,如
配置文件
{
"rules": {
"eqeqeq": "off",
"curly": "error",
"quotes": ["error", "double"]
}
}
注释语法/* eslint quotes: ["error", "double"], curly: 2 */
关闭规则
/* eslint-disable */
alert('foo');
/* eslint-enable */
为指定行指定规则
alert('foo'); // eslint-disable-line no-alert, quotes, semi
- extends 扩展其他配置文件,包括eslint自带的(eslint:recommended, or eslint:all)或者其他shareable config,或者插件带的配置
{
"plugins": [
"react"
],
"extends": [
"eslint:recommended",//eslint自带配置
"plugin:react/recommended"//插件带的配置
],
"rules": {
"react/no-set-state": "off"
}
}
- ignorePattern 指定忽略的文件,如
{
"ignorePatterns": ["temp.js", "**/vendor/*.js"],
"rules": {
//...
}
}
也可以使用.eslintignore文件,注意用forward slashes(/)作为分隔符
# Valid
/root/src/*.js
# Invalid
\root\src\*.js
- overrides:为一部分文件重写规则
{
"rules": {...},
"overrides": [
{
"files": ["*-test.js","*.spec.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}
vscode集成
eslint可以和各种编辑器,各种工具集成,这里只介绍vscode集成,下载eslint插件进行相关配置可以实现保存时检测
"editor.codeActionsOnSave": {
"source.fixAll": true
}
prettier
prettier是一个用于代码格式化的插件,可对前端大部分文件代码按照一定规则进行美化。
它的处理方式是把除了empty lines 和multi-line objects两个样式以外的所有格式清除转化成AST后根据配置的规则重新生成新格式的代码.
prettier专注于对代码格式进行处理,而对代码质量无能为力。
这里还是按三部分来讲:
- 使用方式
- 配置
- vscode集成
使用方式
安装
yarn add --dev --exact prettier
创建一个配置文件让编辑器知道我们在用prettier
echo {}> .prettierrc.json
可以创建一个文件 .prettierignore,指示哪些文件不需要格式化
# Ignore artifacts:
build
coverage
使用prettier进行格式化
npx prettier --write .
把--write换成--check则只检查不进行处理
配置
,而且不同于eslint的细粒度可配置,perttier提供了少量的配置选项,虽然稍微缺乏灵活,但使用起来更加简单。
配置文件和eslint很相似,想查看结构可以参考schema,其他配置参数参考Configuration File
vscode集成
下载prettier插件可设置在保存时对文件进行格式化,但是后面我们会将eslint和prettier结合使用,运行eslint时会自动格式化,因此这里不多讨论。
结合使用eslint和prettier
前面对两个工具做了基本介绍,现在将两者做一下结合,结合之前我们先解决一个问题,就像前面说的,eslint既可以解决代码质量问题也能解决格式问题,为什么还要引入prettier?
这个问题的答案是eslint对于某些格式问题的修复无能为力,比如max-len
(其实涉及到这个问题的基本都拿这一个规则举例子,比如Why You Should Use ESLint, Prettier & EditorConfig),需要用户手动修改才能解决。于是才有了Prettier vs. Linters说的eslint负责代码质量,prettier负责格式的分工。
将两者结合需要解决两个问题,一者快捷执行两个工具的命令,二者关闭eslint中关于格式的规则避免两个工具中规则冲突。这里引入eslint-plugin-prettier和eslint-config-prettie两个辅助包,具体区别可参考What's the difference between prettier-eslint, eslint-plugin-prettier and eslint-config-prettier?。
具体用法:
eslint-plugin-prettier是eslint的一个插件,会作为插件的一部分在执行eslint时自动执行prettier,假设已经按照前面两部分的介绍下载完了eslint和prettier。
安装
yarn add eslint-plugin-prettier --dev
在eslint配置文件上添加
{
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
此时便解决了两个命令同时运行的问题。
继续下载eslint-config-prettie,它提供eslint配置文件,可以使eslint中关于格式的所有规则不可用。
yarn add eslint-config-prettier --dev
在eslint配置文件中的extends数组将plugin:prettier/recommended添加为最后一个
{
"extends": ["plugin:prettier/recommended"]
}
这样解决了格式规则冲突的问题。
从此eslint和prettier便快乐的生活在一起。
githooks
git提供了很多在特定动作发生时触发的钩子,像具体了解gitHooks乃至git可参考 git原理和命令详解:当我们操作git时发生了什么。
在这里我们引入gitHooks主要是为了解决两个问题
- 阻止不规范代码进入代码库
- 规范提交信息 分别对应pre-commit和commit-msg两个钩子,两者解决问题的原理分别是:
- 在执行钩子pre-commit时,为了保证进入commit的都是规范的代码,有两个思路
- 在这个钩子检查代码规范性,如果不规范,则返回1,取消提交
- 在这个钩子fix规范,如果已修复且符合规范则执行
git add
将刚修复的代码加入index,继续执行commit,否则返回1,取消提交
- 在执行钩子commit-msg时,对提交的信息进行检查,如果不符合标准则返回1,取消提交。
下面我们对钩子进行编辑
直接编辑钩子
虽然现在对钩子已经有了比较好的第三方封装,但是我们还是先用最原始的方式进行实现,git的钩子脚本在项目的.git/hooks/目录下,其中包含不同钩子脚本的模板,编辑其中内容(比如替换成下面的脚本),将对应模板的后缀.sample去除,便可在我们对项目进行提交时自动执行。
- pre-commit
对暂存区的文件执行eslint,如果修改完毕则执行
git add
重新加入index,返回返回1失败
for file in $(git diff --cached --name-only | grep -E '\.(ts|tsx)$')
do
echo ":$file"
node_modules/.bin/eslint "$file" --fix #只lint改动的部分
if [ $? -ne 0 ]; then
echo "ESLint failed on staged file '$file'. Please check your code and try again. You can run ESLint manually via npm run eslint."
exit 1 # exit with failure status\
fi
git add "$file" # 把lint过的代码重新添加到index
done
- commi-msg 以提交信息不能小于10为例
#!/bin/sh
MSG=`awk '{printf("%s",$0)}' $1`
if [ ${#MSG} -lt 10 ]
then
echo "-------------------------------------------------------------------"
echo "当前提交的 commit message 为: $MSG"
echo "commit message 只有${#MSG}字符"
echo "message的长度不能小于10, 本次提交失败,请完善commit message,再提交"
echo "-------------------------------------------------------------------"
exit 1
fi
这样便实现了我们想要的功能,但是缺点是这里的脚本不会同步到远程仓库进行复用。
使用第三方工具
这个功能已经有了更好的实现,我们接下来引入三个包
- husky 根据配置修改对应hook文件,实现hook的复用
- lint-staged 配和husky,对将要被commit的文件使用Prettier, ESLint/TSLint, or stylelint等进行格式化,并对格式化的文件重新加入index,继续commit
- commitlint 配和husky,对提交信息进行检查
开始之前,如果我们已经手动改了对应hook文件,需要将其移除,否则将影响husky的使用。
下载三个包
yarn add husky lint-staged --dev
yarn add @commitlint/{cli,config-conventional} --dev
创建commitlint配置文件,指定提交信息根据配置config-conventional来验证,其符合Angular Commit Guidelines的要求。
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js
修改package.json相关配置,参考如下
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.js": "eslint --fix"
}
其中husky字段是husky的配置,其中可以包含各种gitHooks,我们这里只使用其中两个:
当pre-commit时调用lint-staged,即lint-staged的字段,可以根据实际情况进行修改,此demo意为对所有js后缀的文件执行eslint --fix
当commit-msg发生时执行commitlint -E HUSKY_GIT_PARAMS
,其中-E指提交信息所在的文件,默认为.git/COMMIT_EDITMSG
,HUSKY_GIT_PARAMS是husky传给commitlint关于提交信息的参数。
总结
现在我们对代码规范的三个问题有了切实可用的解决方式,虽然我们常用的脚手架,比如vue-cli或者create-react等都内置了相关工具,但是只有从原理上明白它们起作用的原因,才能对其进行进一步调整,乃至自己搭脚手架。
本文对三个功能涉及到的工具做了梳理和解读,其中某些细节处理有待改进,后期会对本内容进行进一步优化更新。
参考
- 按照新的思路再学一遍typescript
- eslint
- prettier
- Why You Should Use ESLint, Prettier & EditorConfig
- eslint-plugin-prettier
- eslint-config-prettie
- What's the difference between prettier-eslint, eslint-plugin-prettier and eslint-config-prettier?
- git原理和命令详解:当我们操作git时发生了什么
- husky
- lint-staged
- commitlint
- config-conventional
- Angular Commit Guidelines