专栏首页云前端[译] 以和为贵!让 ESlint、Prettier 和 EditorConfig 互不冲突

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

原文链接:https://blog.theodo.com/2019/08/empower-your-dev-environment-with-eslint-prettier-and-editorconfig-with-no-conflicts/

ESLint, Prettier and EditorConfig

来由

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

ESLint - Prettier conflict

我曾在一次把 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 包已经解决了这个问题。

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

ESLint no fix

可以看到,那些字符过多或缩进错误的行,都被标以了 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:

eslint-fix-option

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

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 修复,可能会看到这种情况:

Conflict between typescript eslint and prettier

通过禁用新增插件的所有 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 文档(https://github.com/prettier/eslint-config-prettier) 获取可用的 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 时遇到的一摸一样:

Conflict with custom rule

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

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

.prettierrc

{
  "tabWidth": 4
}

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

总结一下这种常见问题:

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

Prettier 和 EditorConfig

设置编辑器配置

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

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

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

.editorconfig

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

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

vscode

避免 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 同样也会遵循。

--End--

查看更多前端好文 请搜索 云前端 或 fewelife 关注公众号 转载请注明出处

本文分享自微信公众号 - 云前端(fewelife),作者:云前端

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-06-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 梳理前端开发使用 eslint 和 prettier 来检查和格式化代码问题

    前端正义联盟
  • 从 ESLint 开始,说透我如何在团队项目中基于 Vue 做代码校验

    最近遇到了一个老项目,比较有意思的是这个项目集前后端的代码于一起,而后端也会去修改前端代码,所以就出现了后端用 IntelliJ IDEA 来开发前端项目,而前...

    用户4456933
  • 代码规范之-理解ESLint、Prettier、EditorConfig

    团队多人协同开发项目中困恼团队管理一个很大的问题是:无可避免地会出现每个开发者编码习惯不同、代码风格迥异,为了代码高可用、可维护性, 如何从项目管理上尽量统一和...

    coder_koala
  • 从 0 开始手把手带你搭建一套规范的 Vue3.x 工程化项目

    Vue3 跟 Vite 正式版发布有很长一段时间了,生态圈也渐渐丰富起来,作者已在多个项目中使用,总结一下:就是快!也不用担心稳定性问题,开发体验真不是一般好!...

    XPoet
  • 从 0 到 1 搭建一个企业级前端开发规范

    https://juejin.cn/post/6947872709208457253

    @超人
  • 前端实用程序包utils - 开发工作流(一)

    早年间有幸在Raychee哥门下当小弟,学到两把刷子。在编程路上,他的很多思想深深影响了我,比如笔者今天要分享的主题。在程序开发中,有个utils包,叫做实用程...

    璀错
  • 一套标准的前端代码工作流

    工欲善其事,必先利其器。对于写代码而言,也是需要有一套完善的工作流(工具和流程)。

    逆锋起笔
  • 前端规范那些事

    以上涉及到的rule规则在扩展包的基础上做了调整,基于两个规范做了修改适合你的规范规则

    树酱
  • 微信小程序安装 WePY框架

    我们在做传统的 Web 开发,会使用到许多框架来提升工作效率,比如:Laravel、Yii等,同样我们开发小程序也应该会使用小程序的一些框架,而 WePY则是专...

    hedeqiang
  • 如何制定企业级代码规范与检查

    就从我的题目说起,本篇文章告诉你针对定制代码规范和检查这个小需求如何做出亮点?看完本文后回顾上面提到的 4 点,感觉下。

    coder_koala
  • 【组件库封装】:封装一个 Library 什么流程?

    在项目开发初期,我们通常会选用主流的UI开发框架来构建应用(例如:基于 React 的 AntDesign、基于 Vue 的 ElementUI)。随着业务研发...

    WEBJ2EE
  • Webpack5 搭建 Vue3 + TS 项目

    https://segmentfault.com/q/1010000024459339

    @超人
  • 使用ESLint+Prettier来统一前端代码风格

    想起自己刚入行的时候,从svn上把代码checkout下来,看到同事写的代码,大括号居然换行了。心中暗骂,这个人是不是个**,大括号为什么要换行?年轻气盛的我,...

    自然醒
  • Vite + React + Typescript 构建实战

    点击上方蓝字,发现更多精彩 导语 最近前端大火的 Vite 2.0 版本终于出来了,在这里分享一下使用 vite 构建一个前端单页应用以及踩过的坑,希望能带给...

    腾讯VTeam技术团队
  • 统一代码风格工具——EditorConfig

    EditorConfig for VS Code EditorConfig官网 微软说明 editorconfig-vscode github

    Jean
  • Vue 项目eslint 配置编程风格(VScode)

    观点:程序运行结果有对错,代码从可读性、扩展性、复用性的标准评判也可以读出来好坏,但是编程风格真的又对错吗?尤其是JS这门脚本语言,在不同领域都有应用,它先天性...

    ZY_FlyWay
  • eslint+prettier学习

    配置文件可以从基本配置扩展启用的规则集,不添加则不会继承任何扩展集,仅按照rules下的基本配置来执行。

    蓓蕾心晴
  • VS Code书写vue项目配置 eslint+prettier 统一代码风格

    以前公司的vue项目只是我一个人在写,代码风格统一,但是后来随着团队增加,统一的代码风格就越来越重要。我的主力工具是sublime,ws辅助,vscode基本很...

    游魂
  • 使用ESLint + Prettier简化代码 Review 过程[每日前端夜话0x4E]

    在最近的一个项目中,我们通过设置 ESLint 和 Prettier 来进行自动化语法检查,并对 JavaScript 项目的代码风格管理。

    疯狂的技术宅

扫码关注云+社区

领取腾讯云代金券