前言
如今,前端工程都已全面推广代码规范化,代码格式便是代码规范化的内在命题之一,eslint提供了静态分析帮助开发者快速发现代码的一些规范问题,并可以借助内置的规则配置集自动地修复不符合最佳实践的代码(当然,这部分能力是有限的)。prettier则重点关注代码格式,不关心代码编写逻辑。
eslint和prettier是功能互补的工具,eslint关注代码编写是否符合最佳实践规范,prettier则专注于代码文件格式化
因此,大多数前端项目都会同时集成eslint
和prettier
,他们两者规则集不同,部分规则存在冲突,于是在实际开发中经常出现使用prettier
格式化后的代码因为eslint
静态检查不通过而无法提交(前提是配置了eslint+prettier+pre-commit
执行提交检查)。
如何利用好两者是一个比较能影响开发体验的问题。本文整理了笔者参与项目中的工程实践,给出eslint
和prettier
两者的配置和使用场景,希望能给大家一些指引。
使用场景关键字:VSCode,React,Typescript。
目标:基于快捷键灵活进行代码格式化和自动修复非规范代码。
prettier
prettier
特性:
- 一个内置规则集的代码格式化工具
- 支持多种语言
- 与大多数编辑器集成
- 简单的配置项
安装
根据官方指引,用户可以本地安装或全局安装 prettier
依赖,这样就能通过npx
指令调用prettier
脚本执行代码格式化。
// 步骤1
// 局部安装
npm install --save-dev --save-exact prettier
// 全局安装
npm install prettier -g
// 步骤2.【可选】在项目根目录生成prettier配置文件
echo {}> .prettierrc.json
// 步骤3.【可选】添加忽略项(对于一些依赖和固定文件,无需格式化)
touch .prettierignore
// 在.prettierignore中添加任意文件or目录名
dist
node_modules
...
// 步骤4.格式化所有文件
npx prettier --write .
嗯,看起来不错,一行命令就可以格式文件,但是...我们需要每次运行命令来格式化文件吗?有没有更灵活快捷的方式呢?
我们有VSCode这个IDE啊,prettier
提供了VSCode插件,可以通过安装prettier
插件,让VSCode具备格式化的能力(应该没人会拒绝,因为快捷键使用起来真的很香!)。所以,推荐的实践是:
- VSCode中安装prettier插件
配置
安装完插件后可以添加自定义配置,这样可以更加灵活地使用prettier
:
- 在项目根目录生成prettier配置文件
echo {}> .prettierrc.json
添加配置项,配置项值可根据习惯自己设置,下面是笔者常用的配置:
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"bracketSpacing": true,
"singleQuote": true,
"printWidth": 120,
"useTabs": false,
"vueIndentScriptAndStyle": true,
"quoteProps": "as-needed",
"jsxBracketSameLine": false,
"jsxSingleQuote": false,
"arrowParens": "avoid",
"insertPragma": false,
"requirePragma": false,
"proseWrap": "never",
"htmlWhitespaceSensitivity": "strict",
"endOfLine": "lf"
}
- 在项目根目录添加
.prettierignore
文件,忽略指定文件or目录
touch .prettierignore
.prettierignore
文件内容示例:
node_modules/
build
dist
使用
安装和配置结束后就可以正常使用了,为了能够通过快捷键驱动prettier
对代码进行格式化,需要先将prettier
设置为VSCode的默认格式化插件:
- 打开 Settings:
- 找到
Format
选项,选择Prettier
作为格式化拓展插件:
当然也可以手动修改settings.json
配置文件:
{
...
// 新增如下配置
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
}
上面的配置项是精确匹配使用prettier
进行格式化的文件类型,如果出现配置中不存在的文件类型,进行格式化时VSCode会让你进行选择默认的格式化扩展插件,届时选择prettier
,VSCode会自动将设置写入到settings.json
中。
完成上面所有步骤后就可以使用VSCode的Format快捷键进行格式化了,当然,开发者也可以自定义快捷键,比如我就就修改成了shift+option+F
作为格式化的快捷键:
eslint
ESLint
是一个用于识别和报告在ECMAScript/JavaScript
代码中发现的代码模式的工具,其目标是使代码更加一致并避免bug。在许多方面,它类似于JSLint
和JSHint
,但有几个独特特征:
- ESLint使用
Espree
进行JavaScript
解析。 - ESLint使用
AST
来评估代码中的模式。 - ESLint是完全可插入的,每一个规则都是一个插件,你可以在运行时添加更多的规则。
安装
同样的,可以安装eslint依赖使得拥有命令行脚本,然后通过npx
驱动eslint
命令对指定文件or目录进行代码检查和修复。
// 项目中安装
npm install eslint --save-dev
// or
yarn add eslint --dev
// 全局安装
npm install eslint -g
// or
yarn add eslint -g
当然,跟安装prettier一样,拥有eslint命令脚本不是我们的目的,我们的最终目标是通过VSCode快捷键完成代码静态检查和自动修复!所以,如何做到这一点呢?
通过eslint的VSCode插件,在VSCode中安装ESLint插件:
安装后的VSCode设置请往下看。
配置
安装成功后,在项目目录执行下面命令生成配置文件:
npx eslint --init
// or
yarn run eslint --init
注意:执行init需要项目已经拥有
package.json
文件。如果项目中没有,可以在项目根目录下先执行npm init
或yarn init
生成一个package.json
文件
npx eslint --init
执行过程(根据提示选择配置选项就行):
生成配置文件后可以添加自定义配置项,这里贴出笔者实际项目中用到的部分配置(项目技术栈React17.0.1
+Typescript4.3.2
):
{
"env": {
"browser": true,
"node": true,
"es6": true
},
"extends": [
"react-app",
"airbnb",
"eslint:recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"eslint:recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"settings": {
//自动发现React的版本,从而进行规范react代码
"react": {
"pragma": "React",
"version": "detect"
},
"import/extensions": [".js", ".jsx", ".ts", ".tsx"],
"import/parsers": {
"@typescript-eslint/parser": [".ts", ".tsx"]
},
"import/resolver": {
"typescript": {
"alwaysTryTypes": true,
"project": [
"./tsconfig.json",
]
},
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"import",
"react",
"@typescript-eslint"
],
"rules": {
"prettier/prettier": 0,
"complexity": ["warn", { "max": 10 }],
"max-len": ["off", { "code": 120 }],
"no-trailing-spaces": "warn",
"quotes": ["warn", "single"],
"react/jsx-indent": "warn",
"react/jsx-indent-props": "warn",
"@typescript-eslint/indent": ["warn", 2, { "SwitchCase": 1 }],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/member-ordering": "warn",
"@typescript-eslint/prefer-optional-chain": "warn",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"format": ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"],
"leadingUnderscore": "allow",
"trailingUnderscore": "allow"
}
],
"@typescript-eslint/consistent-type-assertions": "warn",
"@typescript-eslint/typedef": "warn",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-empty-function": "off",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": "off",
"react/jsx-filename-extension": "off",
"react/jsx-one-expression-per-line": "warn",
"react/jsx-curly-newline": "warn",
"react/jsx-wrap-multilines": "warn",
"react/destructuring-assignment": "off",
"react/display-name": "off",
"react/jsx-props-no-spreading": "off",
"react/jsx-closing-bracket-location": "warn",
"react/no-access-state-in-setstate": "warn",
"object-curly-newline": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/label-has-associated-control": "warn",
"jsx-a11y/click-events-have-key-events": "off",
"react/no-array-index-key": "warn",
"import/prefer-default-export": "warn",
"react/state-in-constructor": "warn",
"react/static-property-placement": "warn",
"react/no-unused-state": "warn",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-debugger": 1,
"@typescript-eslint/ban-ts-ignore": "off",
"import/extensions": "off",
"@typescript-eslint/ban-ts-comment": "off",
"import/no-extraneous-dependencies": "off",
"import/no-unresolved": "error",
"camelcase": "off",
"react/no-unused-prop-types": "off",
"react/require-default-props": "off",
"@typescript-eslint/ban-types": "off",
"no-use-before-define": "off",
"react-hooks/rules-of-hooks": "warn",
"no-shadow": "off",
"curly": "off",
"quote-props": "warn",
"function-paren-newline": "warn",
"@typescript-eslint/no-shadow": ["warn"],
"arrow-parens": ["warn", "as-needed", { "requireForBlockBody": true }],
"implicit-arrow-linebreak": "warn",
"import/no-duplicates": "warn",
"no-confusing-arrow": "warn",
"nonblock-statement-body-position": "warn",
"operator-linebreak": ["warn", "before"]
},
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"rules": {
"react/prop-types": "off"
}
}
]
}
使用(重点)
eslint主要进行代码静态检查和问题修复(基于内置的规则集),所以eslint能够处理的文件一般是逻辑代码文件:js,ts,jsx,tsx...
处理scss,less,css,json等文件不是它的特长!
所以,对于js,ts,jsx,tsx
等文件推荐使用eslint进行代码格式化,对于json,css,less,scss
文件则使用prettier
进行格式化。为此,需要进行以下配置:
- 取消VSCode的
codeActionsOnSave
(可选)
// settings.json文件中增加 or 修改配置,设置source.fixAll.eslint = false
"editor.codeActionsOnSave": {
"source.fixAll.eslint": false
},
取消自动修复的目的是防止代码IDE频繁进行静态代码检查和修复,对于体量巨大的项目尤其需要如此,否则整个IDE会非常卡顿,很影响开发体验。
- 保持
prettier
为默认的代码格式化工具
// settings.json文件
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"diffEditor.ignoreTrimWhitespace": false,
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
- 设置自定义快捷键执行
eslint
代码检查与修复
打开配置:Code -> Preferences -> KeyBoard Shortcuts
找到ESLint: Fix all auto-fixable Problems
配置项,设置快捷键(作者设置是option+F
):
设置后就能灵活地使用option+F
驱动prettier
进行格式化;使用shift+option+F
驱动eslint
进行格式化了!
总结
eslint
和prettier
功能互补而不是互相替代,前者倾向于代码静态检查,适合对js,ts,jsx,tsx
等文件进行“格式化”;后者则专注于代码格式化,可适用于任意脚本文件。eslint
规则和prettier
规则会有冲突的地方,为了避免规则冲突给开发带来困扰,应该分场景使用,对于js,ts,jsx,tsx
等文件用eslint
,对于json,css,less,scss
文件使用prettier
。codeActionsOnSave
开启会消耗IDE较多资源,当代码量庞大时会出现卡顿(作者之前参与过的百万行级项目就遇到过该问题),可根据喜好是否启动;关闭保存自动格式化后可以配置VSCode快捷键弥补无法自动格式化的缺憾。