[Biome博客翻译]Biome赢得了Prettier挑战

589 阅读7分钟

原文:biomejs.dev/blog/biome-… 。以下为翻译。

随着 Biome v1.4.0 的发布,我们赢得了 Prettier 挑战 的奖金!

v1.4.0 中,你将获得更好的格式化体验,更多的格式化选项,新的 VSCode 功能,新的赞助商等等!

你可以通过运行以下命令来升级 Biome:

npm install --save-dev --save-exact @biomejs/biome@1.4.0
pnpm update --save-exact @biomejs/biome@1.4.0
yarn upgrade --exact @biomejs/biome@1.4.0

更好的格式化器

Biome 格式化器现在在与 Prettier 的兼容性上达到了 超过 96%!这个分数是针对 JavaScript、TypeScript 和 JSX 格式化计算的。

这是由 Christopher Chedeau,Prettier 的创造者之一发起的挑战的功劳。

这个挑战吸引了许多人的注意,其中一些人决定为 Biome 做出贡献,以赢得部分奖金。我看到了一些令人惊奇的事情:贡献者们有着惊人的协调能力,他们承担了任务,并在几个小时内提供了解决方案。

我认为使这成为可能的主要因素有三个:

  1. 金钱。这是一个事实,如果有人决定只为了赚取一小部分津贴而做出贡献,那完全没问题。
  2. 沟通。我们使用 GitHub 作为唯一的协调媒介。我们提供了信息、指导和帮助,以便交付。
  3. 基础设施。Biome 依赖于一个坚实的测试基础设施,由 以前的 Rome Tools 员工贡献者 构建。它能够捕获每一个重新格式化的 bug,提供粒度细化的差异,并在发出的输出与 Prettier 发出的输出不同时警告用户。

在挑战之前,Biome 大约有 85% 的兼容性,基于我们的内部指标(JavaScript、TypeScript 和 JSX,在选项平等的情况下)。尽管 85% 看起来可能很高, 但在大型代码库上,低到 15% 的影响是巨大的,人们可能会因为变化太多而感到恐慌,导致早期的采用者在将 Biome 带到他们的团队时遇到阻力。我们社区的一位成员分享了一些见解:

作为一个很好的例子,即使只有最后的 5% 对大型代码库(特别是实现了 bracketSpacing 和现在的 bracketSameLine)的改善有多大,我在我们的单仓库中的一个项目上运行了它[...]。

就在上周,这个数字 [diagnostics] 还超过了 6,000。即使忽略了括号选项,它仍然超过了 1000,现在只剩下 200 了!

尽管挑战已经结束,但我们承诺将进一步提高与 prettier 的兼容性分数。在这方面的任何贡献都非常欢迎。

挑战也揭示了一些我们决定不遵循的 Prettier 的输出案例。我们在网站上创建了一个新的部分来解释它们。我们希望随着时间的推移,这个部分会变得更小。

如果有一个分歧没有在我们的网站上记录,你应该认为那是一个 bug 并提交一个问题。

新的格式化选项

在这个挑战中,我们为格式化器添加了新的选项:

  • lineEnding

    使用此选项来匹配你的操作系统的行结束符。我们支持 lf(换行 - \n)、cr(回车 - \r)和 crlf(回车换行 - \r\n)。

  • bracketSameLine

    // 现有行为。现在也是默认的,意味着 `bracketSameLine: false`。
    <Foo
      className={somethingReallyLongThatForcesThisToWrap}
      anotherReallyLongAttribute={withAValueThatsSurelyTooLong}
      soThatEverythingWraps
    >
      Hello
    </Foo>
    
    <Foo
      selfClosingTags={likeThisOne}
      stillPlaceTheBracket={onItsOwnLine}
      toIndicateThat={itClosesItself}
    />
    

    使用 "bracketSameLine": true 格式化后:

    // 新的行为,`bracketSameLine: true`。
    <Foo
      className={somethingReallyLongThatForcesThisToWrap}
      anotherReallyLongAttribute={withAValueThatsSurelyTooLong}
      soThatEverythingWraps>
      Hello
    </Foo>
    
    <Foo
      selfClosingTags={likeThisOne}
      stillPlaceTheBracket={onItsOwnLine}
    />
    
  • bracketSpacing

    import { sort } from "sort.js";
    const value = { sort };
    

    After formatting with "bracketSpacing": false:

    import {sort} from "sort.js";
    const value = {sort};
    

VSCode 扩展插件的新功能

VSCode 扩展插件已经被移动到一个新的仓库

我们从扩展插件中移除了捆绑的二进制文件,你将能够下载你想要的版本。这里有一个小视频展示了它是如何工作的:

从今天开始,我们发布了一个每夜版本的扩展插件。这是一个为早期采用者和在正式发布之前测试事物的版本。

一些 CLI 的新功能

依赖 Biome LSP 的人将会很高兴,他们现在可以使用选项 --config-path 将自定义配置传递给命令 lsp-proxy。同样的选项也被命令 start 接受:

biome --config-path=../path/where/config/is lsp-proxy
biome --config-path=../path/where/config/is start

CLI 现在公开了选项 --diagnostic-level,允许过滤打印到终端的诊断类型。

biome check --diagnostic-level=error ./src

新的 lint 规则,以及提升的规则

Biome 也是一个 linter,它具有 177 条规则!在这个版本中,一些规则被提升,新的规则也可用。

新规则

  • noDefaultExport

    export default function f() {}
    
    nursery/noDefaultExport.js:1:8 lint/nursery/noDefaultExport ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ⚠ Avoid default exports.
    
      > 1 │ export default function f() {};
          │        ^^^^^^^
        2 │ 
    
      ℹ Default exports cannot be easily discovered inside an editor and don't encourage the use of consistent names through a code base.
    
      ℹ Use a named export instead.
    
    
  • noAriaHiddenOnFocusable

    <div aria-hidden="true" tabIndex="0" />
    
    nursery/noAriaHiddenOnFocusable.js:1:1 lint/nursery/noAriaHiddenOnFocusable  FIXABLE  ━━━━━━━━━━━━━━
    
      ✖ Disallow aria-hidden="true" from being set on focusable elements.
    
      > 1 │ <div aria-hidden="true" tabIndex="0" />
          │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        2 │ 
    
      ℹ aria-hidden should not be set to true on focusable elements because this can lead to confusing behavior for screen reader users.
    
      ℹ Unsafe fix: Remove the aria-hidden attribute from the element.
    
        1 │ <div·aria-hidden="true"·tabIndex="0"·/>
          │      -------------------
    
  • noImplicitAnyLet

    var a;
    a = 2;
    
    nursery/noImplicitAnyLet.js:1:5 lint/nursery/noImplicitAnyLet ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ✖ This variable has implicitly the any type.
    
      > 1 │ var a;
          │     ^
        2 │ a = 2;
        3 │ 
    
      ℹ Variable declarations without type annotation and initialization have implicitly the any type. Declare type or initialize the variable with some value.
    
    
  • useAwait

    async function fetchData() {
      // Missing `await` for the promise returned by `fetch`
      return fetch("/data");
    }
    
    nursery/useAwait.js:1:1 lint/nursery/useAwait ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ✖ This async function lacks an await expression.
    
      > 1 │ async function fetchData() {
          │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      > 2 │ // Missing `await` for the promise returned by `fetch`
      > 3 │   return fetch('/data');
      > 4 │ }
          │ ^
        5 │ 
    
      ℹ Remove this async modifier, or add an await expression in the function.
    
      > 1 │ async function fetchData() {
          │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      > 2 │ // Missing `await` for the promise returned by `fetch`
      > 3 │   return fetch('/data');
      > 4 │ }
          │ ^
        5 │ 
    
      ℹ Async functions without await expressions may not need to be declared async.
    
    
  • useValidAriaRole

    <div role="datepicker"></div>
    
    nursery/useValidAriaRole.js:1:1 lint/nursery/useValidAriaRole  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ✖ Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.
    
      > 1 │ <div role="datepicker"></div>
          │ ^^^^^^^^^^^^^^^^^^^^^^^
        2 │ 
    
      ℹ Check WAI-ARIA for valid roles or provide options accordingly.
    
      ℹ Unsafe fix: Remove the invalid role attribute.
         Check the list of all valid role attributes.
    
        1 │ <div·role="datepicker"></div>
          │      -----------------
    
  • useRegexLiterals

new RegExp("abc", "u");
nursery/useRegexLiterals.js:1:1 lint/nursery/useRegexLiterals  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ⚠ Use a regular expression literal instead of the RegExp constructor.

  > 1 │ new RegExp("abc", "u");
      │ ^^^^^^^^^^^^^^^^^^^^^^
    2 │ 

  ℹ Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.

  ℹ Safe fix: Use a literal notation instead.

    1   │ - new·RegExp("abc",·"u");
      1 │ + /abc/u;
    2 2 │ 

推荐的规则

  • a11y/noAccessKey

    <input type="submit" accessKey="s" value="Submit" />
    
    a11y/noAccessKey.js:1:22 lint/a11y/noAccessKey  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ✖ Avoid the accessKey attribute to reduce inconsistencies between keyboard shortcuts and screen reader keyboard comments.
    
      > 1 │ <input type="submit" accessKey="s" value="Submit" />
          │                      ^^^^^^^^^^^^^
        2 │ 
    
      ℹ Assigning keyboard shortcuts using the accessKey attribute leads to inconsistent keyboard actions across applications.
    
      ℹ Unsafe fix: Remove the accessKey attribute.
    
        1 │ <input·type="submit"·accessKey="s"·value="Submit"·/>
          │                      --------------
    
  • a11y/useHeadingContent

    <h1 />
    
    a11y/useHeadingContent.js:1:1 lint/a11y/useHeadingContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
      ✖ Provide screen reader accessible content when using heading  elements.
    
      > 1 │ <h1 />
          │ ^^^^^^
        2 │ 
    
      ℹ All headings on a page should have content that is accessible to screen readers.
    
    
  • complexity/useSimpleNumberKeys

    ({ 0x1: 1 });
    
    complexity/useSimpleNumberKeys.js:1:4 lint/complexity/useSimpleNumberKeys  FIXABLE  ━━━━━━━━━━━━━━━━
    
      ✖ Hexadecimal number literal is not allowed here.
    
      > 1 │ ({ 0x1: 1 });
          │    ^^^
        2 │ 
    
      ℹ Safe fix: Replace 0x1 with 1
    
    1   │ - ({·0x1:·1·});
      1 │ + ({·1:·1·});
    2 2 │ 
    
    

升级的规则

废弃的规则

这条规则由 correctness/noInvalidNewBuiltin 替换

向我们的维护者致敬

自从 Biome 分叉以来,新的人员加入了项目。他们以你无法想象的多种方式提供了帮助:新功能、辅助项目、与社区的互动、支持、文档等等。开源软件不仅仅是关于编码。

感谢:

以及热烈欢迎我们新加入的维护者:

新的赞助商

最后但并非最不重要的,我们很自豪地宣布我们有两个新的赞助商:

如果你想经济上对项目做出贡献并帮助它发布更多功能,你可以从 GitHub Sponsorship pageOpen Collective page 进行。

下一步是什么

该项目正在蓬勃发展,越来越多的人对项目感到好奇,并希望参与其中。

在接下来的几个月,我们将专注于:

  • 发布路线图。请密切关注,它将涉及许多有趣的工作。
  • 用新的标志重新设计网站。
  • 将网站翻译成日语。