大家好,我卡颂。
配置过代码格式化的同学一定纠结过如下问题:Eslint
和Prettier
都能格式化代码风格,是单用Eslint
,还是两个一起用呢?
从今以后,你再也不用纠结这个问题,因为Eslint
团队已经妥协了 —— 根据官方博客[1]所说,从v8.53.0
起,Eslint
中「代码风格相关规则」将被弃用。
有意思的是,造成上述局面的原因并不是技术问题导致的,更多是市场行为。
本文让我们聊聊事情的来龙去脉。
Eslint的崛起
在2013年之前,前端工程师通常使用JSLint
或JSHint
作为「代码检查器」,用以检测:
- 代码质量问题
比如:应该避免使用 eval()
,应该使用===
而不是==
...
- 代码中的错误
比如:未定义的变量、类型转换的问题...
其中,JSLint
基于内部实现的JS
解析器,对生成的token
流(词法单元流)进行分析,检查代码语法。
JSHint
是从JSLint
派生出来的,他们工作原理类似,但JSHint
更灵活 —— 他提供了.jshintrc
配置文件方便开发者自定义规则。
上述两个工具都能检查代码,但由于实现原理的限制,没法进行复杂的规则检查。同时,他们对「代码风格」的检查也较少。
在这一时期,「代码风格检查」(比如:缩进、行长度、引号类型、是否在语句末尾使用分号...)主要交给JSCS
。
2013年,Eslint
问世。他将代码解析为AST
并分析:
- 相比于
JSHint
或JSLint
的实现,AST
保留了更多代码上下文信息
所以,Eslint
不仅可以进行更复杂的规则校验,还能让开发者以插件的形式自己编写规则。
- 相比于
JSCS
,Eslint
支持「代码自动修复」
所以,Eslint
不仅能对代码风格提出建议,还能自动修复「不符合规范的风格」。
更先进的功能,再加上作者身份加持(作者是红宝书作者),使得Eslint
逐渐淘汰了上述竞品。
Nicholas C. Zakas
Eslint与Prettier之争
虽然Eslint
提供了大量规则,但并不是所有开发者都想配置一套自己的规则集。
慢慢的,一些「Eslint规则集的最佳实践」被提出(比如Airbnb规则[2]、standard规则[3])。
开发者通常会在这些规则集的基础上再做些个性化修改,组成项目的lint
规则集。
这些规则集中,通常包含三类规则:
- 代码质量检查
- 代码错误检查
- 代码风格检查
其中「代码风格检查」通常是非常主观的。如果团队成员的「代码风格检查规则」配置不一样,很影响提交时git diff
的可读性。
为了强制规范「代码风格检查」,Prettier
出现了。这是一款「固执己见」的代码风格格式化工具,他集成了一套代码风格,并且可配置程度不高。
「可配置程度不高」是一把双刃剑,一方面,他能强制规范团队成员的代码风格。
但另一方面,如果想对代码风格做些个性化设置,Prettier
很有可能不支持。
举个例子(来自为什么我不使用 Prettier中的例子),Prettier
中通过printWidth
属性配置「一行可以显示的字符数」,超过就会折行。
有时候我们并不需要「超过某个字符数就折行」,因为在Git Diff
时,折行会破坏Diff
信息的可读性:
然而遗憾的是,Prettier
并没有提供配置关闭这一行为。
基于上述原因,出现了两种解决方案:
方案1 Eslint
与Prettier
配合使用
其中Eslint
负责代码质量、错误检查,Prettier
负责代码风格检查。优点是能够满足代码质量、风格检查。缺点是:
Eslint
与Prettier
规则可能冲突,配置成本高- 代码风格检查的可配置性低(
Prettier
配置性低)
方案2 只使用Eslint
使用「代码风格相关规则的集合」,比如@stylistic/eslint-plugin-js[4]管理代码风格。再使用其他规则管理代码质量。
这种方式优点明显 —— 可配置性高,且配置简单(只需要配置Eslint
)。
显然,方案2是优于方案1的。既然如此,Eslint
团队为什么要弃用所有「代码风格相关规则」呢?
Eslint团队的妥协
设想一下,每当出现新的语言特性,与该特性相关的规则包括:
- 少量的代码质量相关规则
- 少量的代码错误相关规则
- 各种奇怪的代码风格规则
显然前两者的优先级、重要性都高于第三者。如果说,在Eslint
成长初期,为了收割JSCS
的用户,Eslint
必须实现所有「JSCS支持的代码风格规则」,此时实现各种代码风格规则是必要的。
但今时今日,Eslint
早已成为JS
领域「代码检查器」的老大,不需要再为了市场份额努力满足社区的一切需要。况且,有些时候,考虑「规则冲突」以及「一致性」,有些需求甚至无法满足。
规则冲突
最理想的情况,所有核心规则都能很好地相互配合,这意味着没有两个规则应该标记同一个问题,也不会有任何两个核心规则给出相互冲突的建议。
当核心规则少于30条时,这很容易。但对于越来越多的规则,这很难做到。
一致性问题
ESLint
规则之间是无法互相访问的。这意味着我们会遇到无法正确修复错误的问题,因为信息可能位于另一个规则中。
举个例子,如果自动修复需要添加新的代码行,就需要知道文件是如何缩进的,以便应用正确的修复。但是,规则indent
控制ESLint
的缩进,这意味着其他规则需要在不缩进的情况下应用修复,然后相信indent
规则将在后续传递中修复缩进。
总结
ESLint
从v8.53.0
起,将弃用「代码风格相关规则」。这么做主要是因为继续维护「代码风格相关规则」对核心团队来说,投入产出比太低。
试想一下,核心团队花费大力气解决问题(规则冲突、一致性问题),推出新的「代码风格规则」,开发者会感谢Eslint
核心团队的付出么?
不会的,这些「代码风格规则」会被集成到规则集中,并被冠以「某种开发理念」兜售给开发者(比如Airbnb
规范)。
实际收获名利的是站在台前的「宣传开发理念的团队」,而背后辛苦干活的Eslint
核心团队往往被忽略了,换你你乐意么?
参考资料
[1]
官方博客: https://eslint.org/blog/2023/10/deprecating-formatting-rules/
[2]
Airbnb规则: https://airbnb.io/javascript/
[3]
standard规则: https://standardjs.com/
[4]
@stylistic/eslint-plugin-js: https://www.npmjs.com/package/@stylistic/eslint-plugin-js