[译] 以和为贵!让 ESlint、Prettier 和 EditorConfig 互不冲突

简介: [译] 以和为贵!让 ESlint、Prettier 和 EditorConfig 互不冲突

原文链接: blog.theodo.com/2019/08/emp…


来由

如果你已经在搭配使用 Prettier 和 ESLint, 可能已经遇到过 代码格式化冲突 的问题了吧。

image.png

我曾在一次把 TypeScript 项目从 TSLint 迁移到 ESLint 的工作中遇到过这些问题。我们打算用 ESLint 和 Prettier 接管语法检查,在添加了一条 ESLint 规则强制规定 2 个空格缩进以解决上图中的问题后,其他问题又像按下葫芦浮起瓢一样纷纷出现了,很明显没法子通过一条条增加规则解决每一个冲突。

网上关于这个话题的确有很多说法,但大部分都是针对某个特定项目给出一个配置,而非深入阐释为什么 ESLint、Prettier 或 EditorConfig 会八字不合。本文的目的就是对这些潜在的问题解惑,以免相关的 bug 再干扰调试。

策略

我们先来明确一下 各司其职 的原则:

  • EditorConfig 将负责统一各种编辑器的配置,所有和编辑器相关的配置 (行尾、缩进样式、缩进距离...) 都交给它
  • Prettier 作为 代码格式化 工具
  • 其余的,也就是 代码质量 方面的语法检查,用 ESLint 来做

ESLint 和 Prettier

假设我们有这么一个 main.js,并同时配置了 ESLint 和 Prettier。

main.js


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

eslintrc.json


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

让 Prettier 做它自己的工作

为了能 配合使用 ESLint 和 Prettier,应该 关闭所有可能和 Prettier 冲突的 ESLint 规则 (也就是 代码格式化 那些)。好消息是,eslint-config-prettier 包已经解决了这个问题。

bash

代码解读

复制代码

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

先在 .eslintrc.json 中,将 prettier 加到 extends 数组的最后,并移除任何 代码格式化 相关的规则:


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

如此一来, Prettier 的配置将覆盖 extends 数组中先前任何 代码格式化 相关的 ESLint 配置,二者就能并行不悖地工作了。

将 Prettier 整合进 ESLint

分别运行两条命令以检查语法和格式化代码可不太方便,我们可以通过安装 eslint-plugin-prettier 包来解决这个问题。


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

.eslintrc.jsonplugins 数组中加入 prettier 插件,并建立一条指定为  error  的 Prettier 新规则,这样任何格式化错误就也被认为是 ESLint 错误了。


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

main.js 运行 ESLint 试一下:


npx eslint main.js

image.png

可以看到,那些字符过多或缩进错误的行,都被标以了 prettier/prettier 并作为 ESLint 错误被打印出来。

修复之:


npx eslint --fix main.js

文件将按 Prettier 的方式被正确格式化。

Prettier 和 ESLint 配合中的常见问题

添加 ESLint 插件

以上的配置应付小项目绰绰有余;但当你使用 Vue、React 或其他框架时,还是 很容易让 ESLint 和 Prettier 的配置打架。我遇到的一个常见问题是当开发者增加一个 ESLint 插件后,如何在不同时改动 Prettier 的情况下,也能让后者正常工作。

以 TypeScript 为例

出于某些考虑,我们决定在项目中使用 TypeScript。鉴于 TSLint 将被废弃,自然要用 ESLint 取而代之。这里就使用 TypeScript 作为一个例子,来展示 对于有一个适用的 ESLint 插件的框架,该如何处理

这是进行了 TypeScript 改造后的 main.ts 文件:



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

要想让 ESLint 兼容 TypeScript 或是其他什么特殊语法的框架,需要增加一个 parser 以使 ESLint 可以读取新的代码和相关的一系列规则。


npm install typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

然后修改 .eslintrc.json,分别向 parser 选项和 extends 数组中包含 TypeScript 插件:


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

带上 --fix 选项,再来试试 ESLint:

a5583ac2fde29d186018c397f1dd2c27_hid5ykfodc62m_943a3129eeb6420689b502928c95f68f.png

这时如果我们多次执行这条命令,每次都将得到同样的报错 -- 尽管控制台里面说错误是可以被修复的。此时文件被修改为了这样:


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

所以 Prettier 的确格式化了我们的代码,但 ESLint 期望的 4 个空格没有被满足。错误看起来和 @typescript-eslint 规则有关。

如果你像我一样在使用 VSCode 并开启了保存时自动执行 ESLint 修复,可能会看到这种情况:

image.png

通过禁用新增插件的所有 ESLint 格式化规则解决冲突

很多人的一个常见错误就是头疼医头、脚疼医脚。比如对于这个 @typescript-eslint 插件里面的缩进规则,他们会往 rules 数组中添加一条这样的规则:


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

这当然解决了具体冲突,但有两个问题出现了:

  • 无法保证 typescript-eslint 插件中的其他规则今后不和 Prettier 冲突
  • ESLint 和 Prettier 又开始同时负责代码格式化了,这违背了我们的分工策略

按照之前的整合方法,通过在 extends 数组中增加 prettier/@typescript-eslint 来禁用相关插件中所有关乎 代码格式化 的规则。


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

谨记 .eslintrc.jsonextends 数组的顺序非常重要。基本上每次向数组添加新配置时,都将覆盖之前的配置。因此 prettierprettier/@typescript-eslint 待在数组末尾至关重要。

这样配置后就没问题了,ESLint 将不会再越俎代庖。

总结一下这种常见问题:

  • 每当你添加一个 ESLint 插件,针对 它引入的 代码格式化 规则 添加一个 prettier 配置 (如果有的话) 。在我们的例子中,使用了 prettier/@typescript-eslint,但其实我们也可以用 prettier/reactprettier/vue。 检查 eslint\-config\-prettier 文档(github.com/prettier/es…) 获取可用的 ESLint 插件。
  • 不要尝试自己覆盖 eslintrc 中的格式化规则
  • 每当你见到这种 Prettier 和 ESLint 对同一种格式化的冲突,就以为着你有一条无用的 ESLint 格式化规则,也意味着你没有遵守以上两条

添加一条自定义规则

项目团队中的 TypeScript 开发者对 2 个空格缩进浑身不舒服,非要改成 4 个。一个常见的错误是把我们的 ESLint-Prettier 整合策略抛之脑后,并在 .eslintrc.json 中直接添加规则,就像这样:


{
  "parser": "@typescript-eslint/parser",
  "extends": ["plugin:@typescript-eslint/recommended", "eslint:recommended", "prettier", "prettier/@typescript-eslint"],
  "env": {
    "es6": true,
    "node": true
  },
  "rules": {
    "prettier/prettier": "error",
    "@typescript-eslint/indent": ["error", 4]
  },
  "plugins": [
    "prettier"
  ]
}

熟悉的错误毫无意外地又出现了,和我们之前解决 Prettier 协同 ESLint 时遇到的一摸一样:

image.png

rules 数组中自定义的规则会覆盖 prettier/@typescript-eslint 配置。

按照正确的策略,代码格式化 规则应该在 .prettierrc 中配置。对于例子来说,应该是:

.prettierrc


{
  "tabWidth": 4
}

这样 Prettier 将以 4 个空格格式化代码,而 .eslintrc.json 应该不关心任何缩进规则。

总结一下这种常见问题:

  • 当你想添加一条规则时,分清其属于 代码质量 还是 代码格式化 类别。简单地做法是,检查这条规则在 Prettier 中是不是可行的
  • 不要在 .eslintrc.json 中添加格式化规则,这样做将不可避免的和 Prettier 冲突

译注:最新版本 Prettier 已经不需要再配置 prettier/@typescript-eslint


Prettier 和 EditorConfig

设置编辑器配置

EditorConfig 使不同编辑器可以保持同样的配置。因此,我们得以无需在每次编写新代码时,再依靠 Prettier 来按照团队约定格式化一遍(译注:出现保存时格式化突然改变的情况)。当然这需要在你的 IDE 上安装了必要的 EditorConfig 插件或扩展。

本文以 VSCode 为例,但 EditorConfig 支持很多编辑器。

在项目中增加自定义的编辑器配置:

.editorconfig


[*]
end_of_line = lf
charset = utf-8
indent_style = space

如果安装了 the EditorConfig VSCode extension,编辑器将自动获知该如何格式化你的文件。你也能在编辑器右下角看到相应的信息:

image.png

避免 EditorConfig 和 Prettier 的重复配置

但是,这意味着 Prettier 和 EditorConfig 共享了相同的配置选项,而我们不希望同步维护两份重复的配置 (比如关于行尾的配置)。 Prettier 的最新版本通过处理 .editorconfig 文件来决定使用的配置。

限于以下几种选项:


end_of_line
indent_style
indent_size/tab_width
max_line_length

这些选项会被映射为 Prettier 的相关选项 (如果没有在 .prettierrc 再被定义的话):


"endOfLine"
"useTabs"
"tabWidth"
"printWidth"

就像 ESLint 配合 Prettier 时的策略那样,在你改变 EditorConfig 或 Prettier 配置时,根据这些限定选项来决定在哪边改。上面例子中的选项就应该只在 .editorconfig 中存在。

据此再检查我们上面做过的所有配置,还能发现一个配置错误。我们在 Prettier 配置中指定了缩进距离。因为这也是一个浏览器相关的配置,所以应该将其移至 .editorconfig

.editorConfig


tab_width 4

现在我们删除了已经空白的 .prettierrc.json,并对未格式化的代码运行 ESLint:


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

代码缩进变成了 4 个空格。现在,无论你在何时用编辑器打开一个新文件,都会应用这个配置,Prettier 同样也会遵循。



相关文章
|
2月前
|
JavaScript 前端开发 开发者
如何在 VSCode 中使用 ESLint 和 Prettier 检查并自动格式化 Vue.js 代码,提升团队协作效率和代码质量。
【10月更文挑战第9天】随着前端开发技术的发展,代码规范和格式化工具变得至关重要。本文介绍如何在 VSCode 中使用 ESLint 和 Prettier 检查并自动格式化 Vue.js 代码,提升团队协作效率和代码质量。通过安装插件、配置 ESLint 和 Prettier,以及设置 VSCode,实现代码实时检查和格式化,确保代码风格一致。
184 2
|
5月前
|
JavaScript
Vue卸载eslint的写法,单独安装eslint,单独卸载eslint
Vue卸载eslint的写法,单独安装eslint,单独卸载eslint
|
6月前
|
IDE 前端开发 JavaScript
Prettier与ESLint:代码风格与质量的自动化保证
这两个工具协同工作以确保代码一致性。Prettier负责自动格式化,包括缩进、引号等,而ESLint执行静态分析,检查潜在错误和风格。Prettier配置文件如`.prettierrc`,ESLint配置如`.eslintrc.js`。安装它们并集成,例如使用`eslint-plugin-prettier`和`eslint-config-prettier`。在提交前,可通过husky和lint-staged在本地自动运行格式化和检查。IDE中配置插件可实现实时反馈。自定义规则和选择共享配置(如airbnb)以适应项目需求,并在CI流程中集成以保持高标准。
91 1
|
JavaScript
解决eslint 报错的方法
解决eslint 报错的方法
429 1
|
7月前
|
资源调度 JavaScript 前端开发
【源码共读】Vite 项目自动添加 eslint 和 prettier
【源码共读】Vite 项目自动添加 eslint 和 prettier
284 0
|
缓存 Java API
Gradle 构建工具 #5 又冲突了!如何理解依赖冲突与版本决议?
Gradle 作为官方主推的构建系统,目前已经深度应用于 Android 的多个技术体系中,例如组件化开发、产物构建、单元测试等。可见,要成为 Android 高级工程师 Gradle 是必须掌握的知识点。
232 0
Gradle 构建工具 #5 又冲突了!如何理解依赖冲突与版本决议?
|
JavaScript 前端开发
ESLint 和 Prettier 配置冲突解决方案
ESLint 和 Prettier 配置冲突解决方案
|
JavaScript IDE 开发工具
非常规Vue项目配置ESlint和Prettier
这里的非常规指的是,不是使用 `Vue Cli` 这种工具包去创建的项目,或者创建了但是没有加上 `ESlint` 的配置,比如下面这个
|
JavaScript IDE 开发工具
Vue项目优化:编程规范|(一)Eslint + Prettier 统一代码风格
Vue项目优化:编程规范|(一)Eslint + Prettier 统一代码风格
400 0
|
资源调度 JavaScript 前端开发
如何为前端项目一键自动添加eslint和prettier的支持
本文以vite脚手架创建的项目为基础进行研究的,如果是其他脚手架创建的项目,那么就要自己去修改处理,但是原理是一样的。
244 0