本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
前言
在项目团队开发时,经常遇到代码不规范的问题,比如代码没有format、format风格不一致、部分代码明显会导致Bug或其它问题等。这样的代码到了项目后期,会导致无法维护等严重问题。
如何统一开发团队内的代码风格、校验规则?如何去执行和监督?使用ESLint
,配合VSCode
,开发React
项目完美体验。支持高亮不规范代码,保存文件自动格式化,Git commit自动检测等功能。
配置
ESLint 是一个开源的 JavaScript 代码检查工具,用来检查你的代码是否符合指定的规范。文档:中文 | 官方
首先安装ESLint npm包:npm install eslint -save-dev
然后可以通过eslint指令创建eslint config文件:eslint --init
如果提示eslint找不到,可以尝试运行./node_modules/.bin/eslint --init
然后根据提示按需求选择。
这里简单说明下这几个选项:
- How would you like to use ESLint?
- 选项2相比选项1就是多了默认的推荐rules配置,选项3是在2基础上多了format相关rules
- 这里以选项2为例,选项3会在下一篇文章讲到。
- What type of modules does your project use?
- 本文以esm(选项1)为例
- Which framework does your project use?
- 本文以React为例
- Does your project use TypeScript?
- 本文这里选No,没用TS
- Where does your code run?
- 本文选了browser
- What format do you want your config file to be in?
- config文件以什么格式创建,这里选了js格式
- Would you like to install them now with npm?
- 由于上面选了React框架,需要额外安装
eslint-plugin-react
包,这里问是否安装。选Yes
- 由于上面选了React框架,需要额外安装
指令会自动创建.eslintrc.js
文件,如下:
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 13,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
}
};
默认配置里,自动添加了"eslint:recommended"
和 "plugin:react/recommended"
两个官方推荐的rules集合,具体rules可以通过官方文档找到:
然后可以根据自己的需求,在config rules
里添加其它rules,也可以覆盖recommended
里的rules。可以给具体rules设置off
error
warn
等level,具体配置这里就不说了,文档里已经很详细了。
指令
ESLint提供了一些指令,可以扫描单个或多个文件,也可以自动修复支持auto fixable
的rules。
eslint test.js
扫描单个文件eslint .
扫描根路径所有js文件eslint test.js --quiet
只扫描error level ruleseslint test.jsx --fix
扫描文件,并自动修复支持auto fixable
的ruleseslint . --ext .js,.jsx --fix
扫描根路径所有js和jsx文件,并自动修复
命令行里直接运行eslint
指令可能提示找不到指令,可以用./node_modules/.bin/eslint
执行,也可以把eslint install到global里 npm i eslint -g
。推荐把指令加到package.json scripts
里:
"scripts": {
"eslint": "eslint . --ext .js,.jsx",
"eslint:error": "eslint . --ext .js,.jsx --quiet",
"eslint:fix": "eslint . --ext .js,.jsx --fix"
},
如果是React项目,运行之类时可能会抛下面的错误,需要在.eslintrc.js
定义下react version。
// .eslintrc.js
"settings": {
react: {
version: "18.x"
}
},
另外笔者这边项目里的webpack、babel js文件里(包括.eslintrc.js)用的是CommonJS,即 module.exports
这种形式,但是config里配置的是"sourceType": "module"
,导致了提示no-undef
。
一种方法可以定义globals
全局变量,就不会被no-undef
扫出来:
"globals": {
module: "readonly",
require: "readonly",
process: "readonly",
__dirname: "readonly",
},
另一种方法是添加.eslintignore
文件,把部分文件过滤出去,不扫描:
// .eslintignore
node_modules
publish
*.md
.eslintrc.js
webpack.config.js
其它plugin
推荐下一些其它比较好用的plugin,可以方便解决一些特殊需求问题。
- eslint-plugin-react-hooks react hooks lint
- typescript-eslint typescript lint
- eslint-plugin-sonarjs sonar相关lint,推荐参考这篇:juejin.cn/post/720213…
- eslint-plugin-import import相关lint
VSCode
VSCode IDE可以安装 ESLint 扩展插件,支持自动读取.eslintrc.js
配置,在Code里提示对应rules错误,浮动提示,autofix on save等。
设置Extension Settings,这里建议直接设置Workspace下的settings,设置后会在.vscode
路径下生成settings.json
文件,可以提交到git上统一开发团队内部规范。
// .vscode/settings.json
{
"eslint.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true // save文件时自动fix
}
}
另外vscode settings里还有些其它好用的设置,比如类似 semi eol-last 这种rule(format相关的rules),支持autofix,然后敲代码时会经常提示红色的错误,很影响开发体验,总是不自觉的save,这种可以通过settings自定义对应rule的severity,即提示方式,比如下面例子设置为off,这样就不会有红色提示了,并且依然能支持scan和save autofix。
// .vscode/settings.json
{
"eslint.enable": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.rules.customizations": [
{
"rule": "semi",
"severity": "off"
},
{
"rule": "eol-last",
"severity": "off"
}
]
}
Git commit
可以配合git钩子husky
以及lint-staged
,达到git提交时自动检测本次change的code
,如果有规范错误,则commit会失败,并给出eslint具体错误。
npm install husky lint-staged -D
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**": [
"eslint --fix",
"git add"
]
}
Format
ESLint也可以配置一些rules,达到format的效果。比如--init
里自带的airbnb
airbnb
等几种默认代码风格,这部分将在下一篇文章中讲解。
最后
以上就是ESLint的基本知识,还有很多知识有待发掘。通过给项目部署ESLint,可以有效提高代码质量,提高可读性,极大降低团队开发和维护成本。
Code
最后share下项目里经常用到的ESLint配置:
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 13,
"sourceType": "module"
},
"plugins": [
"react",
"react-hooks",
],
"settings": {
react: {
version: "18.x"
}
},
"globals": {
module: "readonly",
require: "readonly",
process: "readonly",
__dirname: "readonly",
},
"rules": {
// off some recommendeds
'react/react-in-jsx-scope': "off",
'react/prop-types': "off",
// hooks
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// enhances error
"semi": "error",
"eqeqeq": ["error", "always", { "null": "ignore" }],
"comma-dangle": ["error", "only-multiline"],
"eol-last": "error",
"radix": "error",
"no-const-assign": "error",
"no-eval": "error",
"no-implied-eval": "error",
"no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }],
"no-self-compare": "error",
"guard-for-in": "error",
"default-param-last": "error",
"array-callback-return": ["error", { "allowImplicit": false, "checkForEach": false }],
"no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }],
"no-shadow": "error",
"no-duplicate-imports": "error",
// enhances warn
"no-unused-vars": ["warn", {
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"vars": "all",
}],
}
};