如何让prettier和eslint更好的一起工作?

1,893 阅读7分钟

背景

在我的项目开发过程中,遇到了一个问题,就像下面视频所展示的那样,typescript/eslint和prettier的规则出现的冲突,导致不管是按照哪个规则去格式化,都会有那条丑陋的红色波浪线,这到底是怎么回事呢?

eslint-prettier-conflict.gif

在我的react项目中,使用了eslint和prettier来进行格式化,很明显,是eslint和prettier的关于缩进的格式化规则出现了冲突。但是为什么会出现冲突呢,究竟应该如果配置才是正确的呢?网上好多资源都是只给出了具体的配置并没有说明为什么,很多人都知道项目中配置EditorConfig+Prettier+ESLint,可以让团队成员在代码开发过程中就检查、约束、美化代码,统一编码风格,但是却不知道为什么。然后在网上看到两篇文章,写得非常好,所以翻译一下供大家一起学习。

这篇文章将尝试着去讲明背后的原因,以后遇到和eslint和prettier相关问题时都能做到有的放矢。

EditorConfig,prettier,eslint

一句话概括:ESLint 将是我们的代码质量检查器,Prettier 是我们的代码格式化工具,而 EditorConfig 将为每个人提供正确的编辑器配置。

JavaScript作为弱类型的动态语言,因为缺少编译阶段,有些本可以在编译过程中发现的错误,只能等到运行时才发现,这给我们调试和提前发现隐藏问题增加了一些难度,而 Lint 工具相当于为js增加了编译过程,在代码部署运行前进行静态分析,找到出错的地方和不规范的代码,并且使用 --fix 对代码进行格式化。

这个时候可能就会有人会问了, 既然已经有了TypeScript,它也能在编译阶段揪出很多代码的问题,什么还需要Lint工具代码检查呢? 因为 TypeScript 关注的重心是类型的检查,而不是代码风格。

Prettier 处理的应该是与代码格式相关的一切,它并不会检查代码的质量。

那这样看来,似乎Prettier能做的事情Eslint也能做,只用Eslint来做代码质量检查和格式检查不就可以了吗?

其实,如果你觉得eslint格式化够用的话,是可以不需要用prettier的。但是在一些情况下,我们是需要prettier配合的,来个小demo试验一下:

main.js

function printUser(firstName, lastName, number, street, code) {
	console.log(`${firstName} ${lastName} lives at ${number}, ${street}, ${code}`);
}
printUser('John', 'Doe', 48, '998 Primrose Lane', 53718, 'Madison', 'United States of America');

注意,我们这个文件中的缩进是四个空格。

给项目安装prettier和eslint

npm install eslint prettier --save-dev

在.eslintrc.js中对规则进行配置:

  1. 允许es6和node语法
  2. 每一行的最大长度为80
  1. 缩进为2个空格
{
  "extends": ["eslint:recommended"],
  "env": {
    "es6": true,
    "node": true
  },
  "rules": {
    "max-len": ["error", {"code": 80}],
    "indent": ["error", 2]
  } 
}

那我们预想应该eslint会报长度和缩进的错。

运行

npx eslint main.js

可以看到

然后使用--fix对格式进行修复

npx eslint main.js --fix

此时我们会看到,缩进的问题已经被eslint修复了,但是max-len的问题依旧存在。

此时我们使用prettier进行格式化:

npx prettier main.js --write

可以看到max-length的问题也被解决了

function printUser(firstName, lastName, number, street, code) {
  console.log(
    `${firstName} ${lastName} lives at ${number}, ${street}, ${code}`
  );
}
printUser(
  "John",
  "Doe",
  48,
  "998 Primrose Lane",
  53718,
  "Madison",
  "United States of America"
);

所以,我们可以看到prettier可以解决一些eslint --fix也无法修复的格式问题,为了到达最佳的代码质量和代码格式的检查,还是推荐prettier和eslint 一起使用,以达到最佳效果。

与编辑器相关的所有配置(行尾、缩进样式、缩进大小...)都应由 EditorConfig 处理,如果一个团队使用两个IDE,例如 Sublime Text 和 Visual Studio Code,EditorConfig 允许他们在单个文件中定义一个通用的缩进模式(空格或tab)。

那么肯定又会有人问了,这个EditorConfig的作用似乎跟prettier差不多,只使用prettier能不能达到一样的效果?

答案是否定的,使用EditorConfig还可以避免在保存时对文件进行无用的格式化,因为编辑器已经根据EditorConfig的规则进行了格式化。但棘手的部分是确保Prettier和EditorConfig具有相同的规则而不是在两个单独的文件中重复配置。

如果您想同时使用ESLint和Prettier,可能会出现格式冲突(我就是遇到了这个问题)。 ESLint 可以用不同于 Prettier 的方式格式化代码。而且,将 EditorConfig 和 Prettier 一起使用可能会使配置冗余。那么,应该如何配置所有这些工具,使它们能够很好地协同工作呢?

让prettier发挥他的作用吧!

为了能够让 Prettier和 ESLint一起使用,我们的想法是停用所有可能与 Prettier(代码格式规则)冲突的 ESLint 规则。其实eslint-config-prettier 包已经帮我们做到了这件事情~

npm install eslint-config-prettier --save-dev

这个插件正是利用prettier中的相关配置去覆盖.eslintrc.json中的配置来做到阻止冲突。

我们将会通过在.eslintrc.json文件中的extends字段的配置来添加prettier并删除原有的任何代码格式。

{
  "extends": ["eslint:recommended", "prettier"],
  "env": {
    "es6": true,
    "node": true
  }
}

注意的一点是:eslintrc.json中的extend的顺序是有讲究的,优先级高的要放后面,后面的配置是会覆盖掉前面的配置的。

运行两个命令来 lint 和格式化我们的文件其实不是很方便。为了解决这个问题,我们将通过添加 eslint-plugin-prettier 包来集成 Prettier 和 ESLint。也就是使用一个命令就是完成我们所需要的lint和格式化的操作。

npm install eslint-plugin-prettier --save-dev

我们将通过在eslintrc.json中的plugins数组中添加prettier插件并将prettier规则设置为error,设置为error之后prettier的格式错误都会被视为ESLint错误。

{
  "extends": ["eslint:recommended", "prettier"],
  "env": {
    "es6": true,
    "node": true
  },
  "rules": {
    "prettier/prettier": "error"
  },
  "plugins": [
    "prettier"
  ]
}

此时,我们的文件将会以prettier的方式去格式化,与此同时,我们还可以使用plugin:prettier/recommended来替换原本.eslintrc.json文件中做的prettier的具体的规则的配置。

此时的.eslintrc.json如下:

{
  "extends": ["eslint:recommended", "plugin:prettier/recommended","prettier"],
  "env": {
    "es6": true,
    "node": true
  }
}

prettier和ESlint的常见问题

这个时候,我看了项目的配置,发现eslint-config-prettier这个依赖已经配置上了,

这样看来,那为什么还会出现冲突呢??因为我们是一个typescript的一个项目,引入了@typescript-eslint 这个插件,prettier要求的是2个空格的缩进,但是eslint要求的却是4个空格的缩进,通过提示,我们可以看到是 @typescript-eslint 这个插件提示的错误,那一般这个时候,我们一般会在.eslintrc.json里面去覆盖掉这个规则:

"@typescript-eslint/indent": ["error", 2]

当这只能解决它表面的问题,下次有别的规则冲突了,我们只能继续在这里添加。

而且像这样去配置的话,eslint和prettier又都开始一起负责格式化的工作了,这是我们不愿意看到的,我们只期望prettier来做格式化的工作。

所以ESLint 不应该进行代码格式化,新添加的插件也不例外。 因此,我们需要通过将 prettier/@typescript-eslint 添加到我们的 extends 数组来禁用插件的所有代码格式规则。

{
  "extends": ["eslint:recommended", "plugin:prettier/recommended","prettier","prettier/@typescript-eslint"],
  "env": {
    "es6": true,
    "node": true
  }
}

因为.eslintrc的extends数组中优先级高的要放后面,因为后面的配置是会覆盖掉前面的配置的,所以prettier和prettier/@typescript-eslint是需要放在数组的最后面。正是因为这个配置,我们可以确保的一点是,eslint不会抢了prettier的格式化这份工作,prettier如果有格式化问题的话,会抛出一个错误给eslint,eslint会报错。

所以我们总结一下

  • 每当在 ESLint 中添加插件时,都必须考虑它添加的代码格式规则并添加prettier的配置(如果可用)以禁用它们。 在我们的例子中,我们使用了 prettier/@typescript-eslint,但我们也可以使用 prettier/react 或 prettier/vue。 查看 eslint-config-prettier 文档以获取支持的 ESLint 插件列表。
  • 不要尝试自己覆盖 .eslintrc.json 文件中的格式规则(这不是 ESLint 的工作范围)
  • 如果你看到你的代码以两种不同的方式格式化,Prettier 和 ESLint 冲突,这意味着你有一个无用的 ESLint 格式化规则产生了这个冲突,并且你没有遵循上述模式(只让prettier来执行格式化的工作)

所以为了解决最前面那个问题,我需要做的,就是在项目中去配置prettier/@typescript-eslint 禁用掉 @typescript-eslint跟prettier冲突的规则,并只让prettier来执行这部分的代码格式化工作。

原文链接

blog.theodo.com/2019/08/emp…

blog.theodo.com/2019/08/why…

www.benmvp.com/blog/pretti…