VUE项目VSCode整合prettier和EsLint,保存代码自动格式化【团队编码风格】
没有耐心看说明和原理的请直接跳转到底部看解决方案。
为什么要使用Prettier和EsLint:
为了在codeview之前就把一些低级错误扼杀在萌芽里,以及统一团队编程风格,基本现在有规模一点的公司都会有自己的一套前端规范。而统一的eslint的配置和prettier的风格限定,是最基本的一项配置,不少公司都会把eslint的配置做成npm包,让团队同学使用。新人开发者,在前期就介入这种规范,有利于行程良好的编码习惯,尽可能提升编码质量。
Prettier简介:
Prettier 是由 Facebook 公司开发的opinionated
的代码格式化工具,它移除了代码的原始风格,并确保所有输出的代码遵守一致的风格。
所谓opinionated
,就是指 Prettier 强制规定了一些风格,你必须按照它指定的方式去组织代码。要是不赞成 Prettier 的风格,就不要使用它。
Prettier 也提供了极少的、必要的配置项,允许用户对一些较有争议的选项进行定制,除此之外的大部分规则都不允许配置,因为配置项越多,关于风格的争吵就会越多。
Prettier 会忽略代码的原始风格,并将代码解析为 AST,按照 Prettier 自己的规则并将最大行长度纳入考虑范围内,将 AST 重新输出为新的风格的代码。
为什么要使用Prettier:
- 构建和强制一套风格指南
- 到目前为止,采用 Prettier 最大的原因是,停止一切正在进行的关于风格的争吵。众所周知,通用的风格指南对项目和团队都是特别有价值的,但是达成通用的风格指南是非常痛苦的过程,也是不值得的。人们对以一种特定的方式写代码是非常有情绪的,没有人愿意花时间写和接受
nits
。 - 因此,选择 Prettier 而不是其他风格指南的原因是,它是唯一自动化的风格指南。即使 Prettier 不能 100% 按照你想要的方式格式化所有的代码,但是鉴于 Prettier 独一无二的优势,有一些“牺牲”也是值得的。
- 到目前为止,采用 Prettier 最大的原因是,停止一切正在进行的关于风格的争吵。众所周知,通用的风格指南对项目和团队都是特别有价值的,但是达成通用的风格指南是非常痛苦的过程,也是不值得的。人们对以一种特定的方式写代码是非常有情绪的,没有人愿意花时间写和接受
- 帮助新手,比如
- 以前使用另一个代码风格指南的人
- 从其他编程语言转过的人
- 编写代码
- 帮助开发者自动格式化代码,节省大量时间
- 易于采用
- …
Prettier 与 Linters
校验工具如 ESLint 等,一般有两类规则:
- 格式化类的规则,比如
- 代码质量类的规则,比如
Prettier 可以完全消除对整个格式化类规则的需要!Prettier 将以一致化的风格重新输出整个项目,因此程序员再也不会有格式化方面的错误了。
但是 Prettier 对代码质量类的规则毫无用处,这也是校验工具提供的最重要的功能,因为它们可以捕获你代码里真正的 bug。
简单点说,我们用ESLint对代码质量类规则进行校验,而编码风格则交给prettier。
ESlint生态介绍:
在说明Eslint配置之前,我们先来掌握Eslint配置的生态圈中涉及到的一些依赖包的作用,这样我们方可以知其所以然。
最基础
- eslint: lint代码的主要工具,所以的一切都是基于此包
解析器(parser)
1.babel-eslint: 该依赖包允许你使用一些实验特性的时候,依然能够用上Eslint语法检查。反过来说,当你代码并没有用到Eslint不支持的实验特性的时候是不需要安装此依赖包的。
2.@typescript-eslint/parser: Typescript语法的解析器,类似于babel-eslint
解析器一样。对应parserOptions
的配置参考官方的README。
扩展的配置
1.eslint-config-airbnb: 该包提供了所有的Airbnb的ESLint配置,作为一种扩展的共享配置,你是可以修改覆盖掉某些不需要的配置的,该工具包包含了react的相关Eslint规则(eslint-plugin-react与eslint-plugin-jsx-a11y),所以安装此依赖包的时候还需要安装刚才提及的两个插件
2.eslint-config-airbnb-base: 与上一个包的区别是,此依赖包不包含react的规则,一般用于服务端检查。
3.eslint-config-jest-enzyme: jest和enzyme专用的校验规则,保证一些断言语法可以让Eslint识别而不会发出警告。
4.eslint-config-prettier: 将会禁用掉所有那些非必须或者和prettier冲突的规则。这让您可以使用您最喜欢的shareable配置,而不让它的风格选择在使用Prettier时碍事。请注意该配置只是将规则off掉,所以它只有在和别的配置一起使用的时候才有意义。
插件
1.eslint-plugin-babel: 和babel-eslint一起用的一款插件.babel-eslint在将eslint应用于Babel方面做得很好,但是它不能更改内置规则来支持实验性特性。eslint-plugin-babel重新实现了有问题的规则,因此就不会误报一些错误信息
2.eslint-plugin-import: 该插件想要支持对ES2015+ (ES6+) import/export语法的校验, 并防止一些文件路径拼错或者是导入名称错误的情况
3.eslint-plugin-jsx-a11y: 该依赖包专注于检查JSX元素的可访问性。
4.eslint-import-resolver-webpack: 可以借助webpack的配置来辅助eslint解析,最有用的就是alias,从而避免unresolved的错误
5.eslint-import-resolver-typescript:和eslint-import-resolver-webpack类似,主要是为了解决alias的问题
6.eslint-plugin-react: React专用的校验规则插件.
7.eslint-plugin-jest: Jest专用的Eslint规则校验插件.
8.eslint-plugin-prettier: 该插件辅助Eslint可以平滑地与Prettier一起协作,并将Prettier的解析作为Eslint的一部分,在最后的输出可以给出修改意见。这样当Prettier格式化代码的时候,依然能够遵循我们的Eslint规则。如果你禁用掉了所有和代码格式化相关的Eslint规则的话,该插件可以更好得工作。所以你可以使用eslint-config-prettier禁用掉所有的格式化相关的规则(如果其他有效的Eslint规则与prettier在代码如何格式化的问题上不一致的时候,报错是在所难免的了)
9.@typescript-eslint/eslint-plugin:Typescript辅助Eslint的插件。
10.eslint-plugin-promise:promise规范写法检查插件,附带了一些校验规则。
辅助优化流程
- husky: git命令hook专用配置.
- lint-staged: 可以定制在特定的git阶段执行特定的命令。
这是用husky前置提交钩子,在代码上传到Git前进行强制的校验,目前很多架子都会看到这玩意儿,包括vue cli生成的项目都可以往里面加入这种强校验,如果对代码质量要求很高可以启用这个工具,但是我司因为存在很多老项目,老项目代码质量不一,并不适合加入此工具。
Prettier
Prettier相关的包有好多个,除了上面列举的两个,你可能还会用到下面的三个:
- prettier:原始实现版本,定义了prettier规则并实现这些规则。支持的规则参考:传送门
- prettier-eslint:输入代码,执行prettier后再eslint –fix输出格式化后的代码。仅支持字符串输入。
- prettier-eslint-cli:顾名思义,支持CLI命令执行prettier-eslint的操作
那么Prettier这么多工具包,都是些什么关系呢?太容易让人混淆了。这里用一段话简单介绍一下:
**最基础的是prettier,然后你需要用eslint-config-prettier去禁用掉所有和prettier冲突的规则,这样才可以使用eslint-plugin-prettier去以符合eslint规则的方式格式化代码并提示对应的修改建议。为了让prettier和eslint结合起来,所以就诞生了prettier-eslint这个工具,但是它只支持输入代码字符串,不支持读取文件,因此又有了prettier-eslint-cli
VsCode和ESLint整合,保存时自动格式化代码
1.按下保存按钮的时候自动修复低级错误且格式化代码
2.修复的时候是读取项目根目录的eslint规则以及prettier配置文件
VSCode插件安装:
在VSCode的拓展中心找到eslint插件和prettier插件
安装npm依赖包
安装了VSCode的插件,插件介绍里面也说的很清楚,需要安装相应的npm包配套一起使用,使拓展和VSCode整合。
在此我们需要安装这些npm依赖包:
- eslint
- prettier
- babel-eslint(作为解析器,上面有介绍)
- @vue/eslint-config-prettier或者eslint-config-prettier(用于关闭那些不需要或与 Prettier 冲突的 ESLint 规则)
- eslint-plugin-prettier(将Prettier的解析作为Eslint的一部分)
- eslint-plugin-vue(用来解析.vue文件)
执行这些依赖包的安装:
npm i eslint prettier eslint-config-prettier babel-eslint eslint-plugin-prettier eslint-plugin-vue -D
复制代码
项目依赖中可能已经有了这几个eslint的相关宝,如果直接用上述命令安装控制台依赖关系报错(大多是因为已经存在比较老的版本跟要安装的版本冲突),请卸载掉原有eslint和prettier相关包再执行安装命令。
@babel/eslint-parser
该 parser 允许你使用 ESLint 校验所有 babel code。
ESLint的默认解析器和核心规则仅支持最新的最终 ECMAScript 标准,不支持 Babel 提供的实验性(例如新功能)和非标准(例如Flow或TypeScript类型)语法。@ babel / eslint-parser 是允许 ESLint 在由 Babel 转换的源代码上运行的解析器。
当你使用 babel 时,babel 的解析器会把你的 code 转换为 AST,该解析器会将其转换为 ESLint 能懂的 ESTree。
ESLint的核心规则不支持实验性语法,因此可能无法正常工作,需要使用 @babel/eslint-plug 规则集。并且 ESLint 官方文档中的 parserOptions 只适用 Espree 解析器
eslint-config-prettier
eslint-config-prettier
是 ESLint 的配置库,用于关闭那些不需要或与 Prettier 冲突的 ESLint 规则。这可以让你在使用 Prettier 时,可以使用你最喜欢的 ESLint 共享配置而不使用该共享配置里有关样式的规则。注意,这个配置只是关闭规则,因此仅在与其他配置一起使用时才有意义。
若是单独使用eslint-config-prettier
(即不使用eslint-plugin-prettier
),则应该如下继承配置:
// .eslintrc.*
{
"extends": ["some-other-config-you-use", "prettier"]
}
复制代码
因为eslint-config-prettier
是要关闭其他配置的样式规则,所以必须放在其他 ESLint 配置之后。extends选项里面可以省略包名前缀,如这里就可以直接写成prettier。
eslint-plugin-prettier
eslint-plugin-prettier
是使用 Prettier 进行格式化的 ESLint 插件,它会将 Pretter 作为 ESLint 的一条规则来运行并进行格式化,然后与格式化之前的代码进行对比,如果出现了不一致,这个地方就会被 Prettier 进行标记并报告出来。
若是单独使用eslint-plugin-prettier
(即不使用eslint-config-prettier
),则应该如下进行配置:
// .eslintrc.*
{
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
复制代码
若是你禁用了所有其他与代码格式化相关的 ESLint 规则,则eslint-plugin-prettier
插件将工作地最好。若是使用了另一个在代码格式化方面与 Prettier 不一致的 ESLint 规则,则引起校验错误是无可避免的。正如上面eslint-config-prettier
所介绍的,你可以使用eslint-config-prettier
来禁用所有 ESLint 的与格式化相关的规则。
eslint-config-prettier 和 eslint-plugin-prettier 的集成
因此,正常情况下,会同时使用eslint-plugin-prettier
和eslint-config-prettier
,其配置为:
// .eslintrc.*
{
"extends": [
"some-other-config-you-use",
"prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
复制代码
plugins
属性值 可以省略包名的前缀 eslint-plugin-
。
extends
属性值可以由以下组成:
plugin:
- 包名 (省略了前缀,比如,
react
) /
- 配置名称 (比如
recommended
)
推荐配置
以上这种方式的集成配置较为繁琐,eslint-plugin-prettier
提供了一种简单的配置方式。
// .eslintrc.*
{
"extends": ["plugin:prettier/recommended"]
}
复制代码
上面这一行配置做了三件事情:
- 启用了
eslint-plugin-prettier
插件 - 设置了
"prettier/prettier"
规则为"error"
- 继承了
eslint-config-prettier
配置
若是打开node_modules/eslint-plugin-prettier/eslint-plugin-prettier.js
文件,可以看到:
module.exports = {
configs: {
recommended: {
extends: ["prettier"],
plugins: ["prettier"],
rules: {
"prettier/prettier": "error"
}
}
}
// ...
};
复制代码
即"extends": ["plugin:prettier/recommended"]
这一行实际上是以下配置的缩写方式。
{
"extends": ["prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
复制代码
配置 Prettier 规则
以上的配置都是使用的 Prettier 的默认配置,若是想要自定义 Prettier 的配置,需要做两件事情:
- 针对不会被 ESLint 格式化的文件类型,需要在项目根目录添加一个
.prettierrc
的配置文件 - 针对会被 ESLint 格式化的文件类型,Prettier 会作为 ESLint 的一个规则运行并格式化文件,因此需要在
.eslintrc.*
的rule
里添加如下配置
.prettierrc
配置如下:
{
"printWidth": 130,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"arrowParens": "avoid",
"bracketSpacing": true,
"jsxBracketSameLine": true,
"endOfLine": "auto",
"eslintIntegration": true,
"htmlWhitespaceSensitivity": "ignore",
"trailingComma": "all"
}
复制代码
为了支持特殊的 ESLint 插件(比如,eslint-plugin-vue
),你可以如下添加额外的配置:
.eslintrc.*
配置如下:
{
// 自定义 parser,详见 https://eslint.vuejs.org/user-guide/#how-to-use-custom-parser
"parserOptions": {
"parser": "babel-eslint"
},
"extends": [
// 使用 eslint-plugin-vue 插件,并继承 eslint-config-vue 的 recommended 配置
"plugin:vue/recommended",
"plugin:prettier/recommended",
"prettier/vue"]
}
复制代码
extends选项从左到右,因为eslint-config-prettier解决冲突需要放在最后生效,所以这里如果有其他的配置或者插件(我司的架子里面还有一些typescript的插件和npm包配置,都可以写在前面
plugin:vue/recommended 隐含的配置
在上述extends中我们使用了”plugin:vue/recommended”,这一行,打开node_modules/eslint-plugin-vue
可以看到,若是在extends
里添加了plugin:vue/recommended
,默认会包含以下配置,因此这些配置我们都不需要显示写在.eslintrc
里。
// node_modules/eslint-plugin-vue/lib/configs/base.js
// recommended 继承了 base
module.exports = {
parser: require.resolve("vue-eslint-parser"),
parserOptions: {
ecmaVersion: 2018,
sourceType: "module",
ecmaFeatures: {
jsx: true
}
},
env: {
browser: true,
es6: true
},
plugins: ["vue"],
rules: {
"vue/comment-directive": "error",
"vue/jsx-uses-vars": "error"
}
};
复制代码
VSCode配置
VSCode的配置,可以在VSCode的设置选项可以设置,也可以写成全局的VSCode,但是为了不污染其他没有使用eslint和prettier的项目,所以这里建议是写成项目的配置。在项目根目录新建一个.vscode文件夹,文件夹内新建一个设置的json文件,名字为settings.json。
{
// Format a file on save. A formatter must be available, the file must not be auto-saved, and editor must not be shutting down.
"editor.formatOnSave": true,
// 设置文件默认的格式化工具为 Prettier - Code formatter
// 当文件存在多个 VS Code 的 formatter 插件对同一个文件类型进行格式化时,需要手动选择 prettier-vscode 即 Prettier - Code formatter 插件
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
// 关闭编辑器对 js 文件的格式化,交给 ESLint 来做格式化,否则会格式化两次
"editor.formatOnSave": false
},
// Eslint 插件配置,详见 https://github.com/microsoft/vscode-eslint
// Enables auto fix on save. Please note auto fix on save is only available if VS Code's files.autoSave is either off, onFocusChange or onWindowChange. It will not work with afterDelay.
"eslint.autoFixOnSave": true,
"eslint.alwaysShowStatus": true,
// An array of language ids which should be validated by ESLint
"eslint.validate": [
{
"language": "html",
"autoFix": true
},
{
"language": "javascript",
"autoFix": true
},
{
"language": "vue",
"autoFix": true
}
],
// Vetur(若安装了此插件的话)
// 关闭 vetur 的格式化功能
"vetur.format.enable": false,
// 关闭 vetur 对 template 的检查,交给 eslint,详见:https://vuejs.github.io/vetur/linting-error.html#linting-for-template
"vetur.validation.template": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
复制代码
主要的配置内容有:
- 关闭 Vetur 对文件的格式化及对
<template>
的检查(若是存在 Vetur 插件) - 启用 ESLint 插件对文件的自动格式化和修复功能
- 设置文件的格式化工具为 Prettier – Code formatter(当出现对同一文件类型的多个 formatter 时,需要手动选择使用 Prettier – Code formatter)
以上配置文件写的很清楚,这里跟全局冲突的配置文件会覆盖掉全局的配置文件,且只在本项目中生效。eslint中的一些配置项也会随着插件和npm包的更新而改变,如果遇到没有生效的地方,自己搜索相应文档。
此处有一点需要注意,我司架子项目中eslint的解析器是typescript相关的解析器,以及在extends里面也加入了TS相关配置,我的做法是直接去掉相关的npm包以及文件和配置,因为自己写的项目中没有写TS的东西,这样也可以精简一下项目。
babel 支持解析 Typescript sourcecode,对于一些 Typescript 目前还不支持的语法,babel 可以解析,就像 js 需要使用 babel 一样。所以 Typescript Complier 不支持语法的 babel 支持。
如果在 Typesciprt 中使用了 babel,而 ESLint 的 parser 又是使用的 @typescript-eslint/parser 和其提供的 rules,由于 @typescript-eslint/parser 底层是依赖 Typescript complier 作为编译器,而 babel 转换时使用的是其自己的编译器,两者不一致,可能会出现使用了 babel 中支持而 Typescript complier不支持的 Typescript 语法,然后 ESLint 报错的情况。出现这种情况,有两种解决方式。
- 将 ESLint 的 parser 和 rules 替换为前面提到的 @babel/eslint-parser 和对应的 rules,这样就不会出现 babel 和 ESLint 的 parser 不一致
- 继续使用 @typescript-eslint/parser 和其提供的 rules,因为它支持我们自定义 rules,可以去社区找找对应的语法是否已经存在相关的 rule,或者自己编写。
终极配置方法:
以上讲的可能太长没有什么耐心看,那么可以尝试使用vue cli的命令添加eslint和相关配置,架子里面的脚本如果在当大部分项目中都是可以直接添加免除这么多繁琐的配置过程的,上面赘述是因为架子的脚本在添加的时候也会遇到各种错误,如果出现错误你也能手动配置,或者根据原理拍错。
vue add eslint
复制代码
全局安装vue cli后,使用文档中插件那个章节的添加命令,按照提示符选择prettier相关选项,就可以整合进去,执行这条命令之前一定要git add .保存一下!!!以免出错的时候不好还原。然后根据上述说明,直接配置VSCode的项目内配置文件,以及prettier的配置文件,prettier格式化的时候如果换行比较多,请更改.prettierrc文件中的printWidth字段数值,更多选项说明请自行搜索prettier文档。这样保存时自动格式化和纠错就完成了。