🌲

フォーマッターとリンターを兼ね備えた「Biome」を触ってみる

2023/10/02に公開

Biomeとは

Romeのコアメンバー達が新しく開発したツールです。
Romeはフォーマッター、リンター、テスト、トランスパイラ、バンドラなどのチェンツールを1つで担っていましたが、Biomeでは現在(2023年10/2)フォーマッターとリンターの機能のみを提供しています。

導入

Romeからの移行も簡単に出来るようです。以下の記事が参考になります
https://zenn.dev/gmomedia/articles/263eb7af50c216

インストール

npm install --save-dev --save-exact @biomejs/biome
or
yarn add --dev --exact @biomejs/biome
or
pnpm add --save-dev --save-exact @biomejs/biome
or
bun add --dev --exact @biomejs/biome

設定ファイルを生成する

pnpm biome init

Biomeの設定ファイルがプロジェクト直下に生成されます

biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.2.2/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}

vscodeで使えるようにする

  1. vscodeの拡張機能をインストールします

  2. .vscode/extensions.jsonで拡張機能のレコメンドもしましょう

.vscode/extensions.json
{
  "recommendations": [
    "biomejs.biome"
  ]
}
  1. .vscode/settings.json に設定を追加します

    詳しい詳細

    formatterの設定

    • js, jsx, ts, tsxファイルをBiomeが担当
    • それ以外はここではPrettierに任せます
    .vscode/settings.json
    {
      "editor.formatOnSave": true,
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "[javascript]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[javascriptreact]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[typescript]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[typescriptreact]": {
        "editor.defaultFormatter": "biomejs.biome"
      }
    }
    

    lintの設定

    • 保存時にlinterを走らせる
    settings.json
    {
      "editor.codeActionsOnSave": {
        "quickfix.biome": true
      }
    }
    

    Analyzerの設定

    • 保存時にimportのソートを実行
    .vscode/settings.json
    {
        "editor.codeActionsOnSave":{
            "source.organizeImports.biome": true
        }
    }
    

    全体のまとめ

    .vscode/settings.json
    {
      "editor.formatOnSave": true,
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "[javascript]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[javascriptreact]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[typescript]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "[typescriptreact]": {
        "editor.defaultFormatter": "biomejs.biome"
      },
      "editor.codeActionsOnSave": {
        "quickfix.biome": true,
        "source.organizeImports.biome": true
      }
    }
    

コマンドを試す

コマンドの一覧

  • version: Biomeバージョンの情報を表示して終了
  • rage: デバッグの情報を印刷
  • start: Biomeデーモンサーバープロセスを開始する
  • stop: Biomeデーモンサーバープロセスを停止する
  • check: 一連のファイルに対してさまざまなチェックを実行します。
  • lint: 一連のファイルに対してlintterを実行します。
  • format: 一連のファイルでformatterを実行します。
  • ci: CI環境で使用するコマンド。一連のファイルのさまざまなチェックを実行します。
  • init: 新しいバイオームプロジェクトをブートストラップします。一部のデフォルトで構成ファイルを作成します。
  • lsp-proxy: stdin / stdout上のLanguage Server Protocolのサーバーとして機能します
  • migrate: 変更が発生したときに構成を更新します

formatterのコマンド

pnpm biome format ./src

書き換える時は --writeを追加します

pnpm biome format --write ./src

lintterのコマンド

pnpm biome lint ./src

書き換える時は --applyを追加します

pnpm biome lint --apply ./src

biome.jsonのプロパティ

ここ見る

  • $schema
    • Biomeのバージョン
    • biome.jsonファイルで使うプロパティの型のようなもの
  • extends
    • ファイルパスを指定して、他の設定ファイルを継承できる
  • files
    • maxSize
      • バイト単位のソースコードファイルの最大許容サイズ デフォルト:1024 * 1024 ( 1MB )
    • ignore
      • 無視するファイルパス。配列で書く
    • allowUnknown
      • 処理できないファイルに遭遇した場合、検出するか
  • vsc
    • Version Control System
    • BiomeをVCSソフトウェアと統合するための一連のプロパティ。
  • linter
    • enable
      • 許可する
    • ignore
      • 除くファイルパス
    • rules
      • リンターの設定(後に紹介します)
  • formatter
    • フォーマッターの設定(後に紹介します)
  • organizeImports
    • アナライザーの設定(後に紹介します)
  • javascript
    • JS・TSのみ効く設定
    • parser.unsafeParameterDecoratorsEnabled
      • 安全でない/実験的なパラメーターデコレーターをサポートできます。
    • formatter
      • フォーマッターの設定(後に紹介します)
    • globals
      • 無視するグローバル名
  • json
    • jsonのみ効く設定
    • parser
      • allowComments
        • コメントを許可
      • allowTrailingCommas
        • 末尾のカンマを許可
    • formatter
      • フォーマッターの設定(後に紹介します)

Anlyzer

アナライザーは、ユーザーが活用できる一連の機能を提供しています。現在はorganizeImportsだけ提供しているみたいです。

biome.json
{
  "organizeImports": {
    "enabled": true
  }
}

ソートは以下のように実行されます

  1. importの行のソート
    • 参照先(from)で大文字をアルファベット順 → 小文字をアルファベット順
  2. importの{}の中のソート
    • 大文字をアルファベット順 → 小文字をアルファベット順

ソート前

import { aa } from 'z'
import { a, B, c, D } from 'a'
import { C } from 'c'
import { b } from 'B'
import { d } from 'D'

ソート後

import { B } from 'B'
import { D } from 'D'
import { B, D, a, c } from 'a'
import { c } from 'c'
import { aa } from 'z'

改行があると、そのまとまりで上記のようにソートされる

ソート前

import { aa } from 'z'
import { a, B, c, D } from 'a'
import { B } from 'B'

import { c } from 'c'
import { D } from 'D'

ソート後

import { B } from 'B'
import { B, D, a, c } from 'a'
import { aa } from 'z'

import { D } from 'D'
import { c } from 'c'

注意点

  • グループ化は自分で改行いれる必要がある
  • 並び順をカスタマイズ出来ない
  • 使っていないのを削除、重複で削除、fromが同じなら合体等は出来ない

formatter

フォーマットには3種類あります

  • formatter: 全てのファイルのルール
  • javascript: js, ts, jsx, tsxのルール
  • json: jsonのルール

全体のformatterの設定

全体の"formatter"の詳細

プロパティはPrettierと同じなので取っつきやすいです

  • formatWithErrors: ファイルに構文エラーがある時に、フォーマットを許可するかどうか
biome.json
{
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "ignore": [],
    "indentSize": 2,
    "indentStyle": "space",
    "lineWidth": 80
  }
}

javascriptのformatterの設定

"javascript"のformatterの詳細
js, ts, jsx, tsxで使用されるフォーマッターのルールです。
ここもPrettierと同じなので取っつきやすいです

biome.json
{
  "javascript": {
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    },
    "formatter": {
      "enabled": true,
      "quoteStyle": "single",
      "jsxQuoteStyle": "single",
      "trailingComma": "all",
      "semicolons": "asNeeded",
      "arrowParentheses": "asNeeded",
      "indentSize": 2,
      "indentStyle": "space",
      "lineWidth": 80,
      "quoteProperties": "asNeeded"
    }
}

jsonのformatterの設定

"json"のformatterの詳細

biome.json
{
  "json": {
    "parser": { "allowComments": true },
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentSize": 2,
      "lineWidth": 80
    }
  }
}

linter

ルールの値は、error, warn, offの3段階で設定できます。これはESLintの2,1,0とも同じですね。
また、オプションがあるルールもあり、ルール: {level: "error", options: {...}}のように設定できます。

以下は用途ごとに分類分けしたものです。これらの中にルールが複数存在するのでそれを確認して設定していきます。

  • a11y
    • アクセシビリティの問題を防ぐことに焦点を当てたルール。
  • complexity
    • 簡略化できる複雑なコードの検査に焦点を当てたルール。
  • correctness
    • 正しくないか役に立たないことが保証されているコードを検出するルール。
  • performance
    • コードをより速く実行するように記述する方法、または一般的により効率的にする方法をキャッチするルール。
  • security
    • 潜在的なセキュリティ欠陥を検出するルール。
  • style
    • コードを一貫して慣用する方法で作成するルール。
  • suspicious
    • 正しくないか役に立たない可能性が高いコードを検出するルール。
  • nursery
    • まだ開発中の新しいルール。
    • バグやパフォーマンスの問題がまだある可能性があるため、安定バージョンの構成による明示的なオプトインが必要です。 これらは毎晩のビルドでデフォルトで有効になっていますが、不安定であるため、診断の重大度はエラーまたは 最終的に安定したときにルールを推奨するかどうかに応じて、警告。 保育園のルールは、安定するか削除されると、他のグループに昇格されます。
    • このグループに属するルール セマンティックバージョンの対象ではありません

また、Biomeではrulesallrecommendedプロパティが使うことが出来てとても便利です。
rulesの直下で使うと全てのルールに適用されるので、recommended: trueで設定し、biome lintで確認をして合わないルールがあれば個別でoffにするのが良いかと思います。

以下は用途ごとに分類分けしたルールで、それぞれall, recommendedプロパティが使えます。なので、例えばa11yall: true, complexityrecommended: trueのような設定が出来ます。便利ですね!

以下のようにrulesの設定をすることが出来ます

{
  "linter": {
    "rules": {
      "a11y": {
        "noAccessKey": "error",
        "noAriaUnsupportedElements": "warn",
        "noAutofocus": "off",
        "noBlankTarget": {
          "level": "error",
          "options": {
            "strictCase": false,
            "enumMemberCase": "CONSTANT_CASE"
          }
        }
      },
      "complexity": {
        "recommended": true
      },
      "performance": {
        "all": true
      }
    }
  }
}

最終形態

最終的なbiome.jsonは以下のようになりました!
linterのルールはぱっとしか見れてないのでご了承

biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.2.2/schema.json", // Biomeのバージョン
  "extends": [], // ローカルの設定ファイルを継承できる
  "files": { "ignoreUnknown": true }, // 処理できないファイルに遭遇した場合、検出するか
  "organizeImports": {
    "enabled": true // importのソートをする
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false, // ファイルでエラーがある時フォーマットをしない
    "ignore": [],
    "indentSize": 2,
    "indentStyle": "space",
    "lineWidth": 80
  },
  "javascript": {
    "parser": {
      "unsafeParameterDecoratorsEnabled": true // 安全でない/実験的なパラメーターデコレーターをサポートする
    },
    "formatter": {
      "quoteStyle": "single",
      "jsxQuoteStyle": "single",
      "trailingComma": "all", // 末尾のオブジェクトにカンマを付ける
      "semicolons": "asNeeded",
      "arrowParentheses": "asNeeded" // 関数のPropsが一つなら()で括らない
    }
  },
  "json": {
    "parser": { "allowComments": true }, // コメントを許可
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentSize": 2,
      "lineWidth": 80
    }
  },
  "linter": {
    "ignore": [],
    "rules": {
      "a11y": {
        "noAriaUnsupportedElements": "error", // ARIAの役割、状態、およびプロパティをサポートしない要素には、これらの属性がないことを強制
        "noBlankTarget": "error", // target="_blank"を使う時、rel=“noreferrer”を強制
        "noDistractingElements": "error", // 存在しない要素でエラー
        "noNoninteractiveElementToInteractiveRole": "error", // インタラクティブなARIAロールが非インタラクティブHTML要素に割り当てられないように
        "noPositiveTabindex": "error", // tabIndexで整数使うとエラー
        "noRedundantAlt": "error", // 暗黙的なロールでのroleの使用でエラー
        "useAltText": "error", // alt必要な要素で強制
        "useAriaPropsForRole": "error", // ARIAロールで必須のARIA属性を強制
        "useHtmlLang": "error", // HTMLのlangを使う
        "useIframeTitle": "error", // iframeでtitleを強制
        "useMediaCaption": "error", // audio, video要素で、track要素を強制
        "useValidAnchor": "error", // すべてのアンカーが有効である
        "useValidAriaProps": "error", // 正しいaria-*を使う
        "useValidAriaValues": "error", // 正しいARIAを使う
        "useValidLang": "error" // lang属性で正しい言語・国を使う
      },
      "complexity": {
        "noBannedTypes": "warn", // 誤解を招く型でエラー
        "noExtraBooleanCast": "error", // 無駄なBooleanでエラー
        "noForEach": "warn", // forEachでエラー。for ofを使う
        "noMultipleSpacesInRegularExpressionLiterals": "error", // 正規表現の連続スペースでエラー
        "noStaticOnlyClass": "error", // staticだけのclassでエラー
        "noUselessConstructor": "error", // 無駄なconstructorでエラー
        "noUselessRename": "error", // 無駄な as でエラー
        "noUselessSwitchCase": "error", // 無駄なswitchのcaseでエラー
        "useLiteralKeys": "error", // オブジェクトで、 a[b]ではなく、a.bを使う
        "useOptionalChain": "error", // オプショナルチェーンを使うようにする
        "useSimplifiedLogicExpression": "error" // 無駄な論理式でエラー出す 例) const bool =  true || foo
      },
      "correctness": {
        "noChildrenProp": "error", // コンポーネントのchildrenをPropsで渡すとエラー
        "noConstAssign": "error", // constを再代入でエラー
        "noConstantCondition": "error", // 条件式の中身が定数でエラー(確定するから)
        "noEmptyPattern": "error", // 空のオブジェクトを禁止 const {} = a, const {a: {}} = foo
        "noPrecisionLoss": "error", // 桁数の多すぎる数字でエラー(制度が落ちる)
        "noRenderReturnValue": "error", // ReactDOM.renderの代入を許可しない const foo = ReactDOM.render()
        "noSelfAssign": "error", // a = aを許可しない
        "noSetterReturn": "error", // classのsetメソッドが値を直接返すのを禁止
        "noStringCaseMismatch": "error", // 違う文字のCaseとの比較でエラー 例)toUpperCaseした文字と、そうでない文字との比較
        "noUnnecessaryContinue": "error", // ループ文の最初でcontinueするとエラー
        "noUnreachable": "error", // 到達不可能なコードでエラー
        "noInvalidConstructorSuper": "error", // extendsしてたらconstructorでsuperを強制
        "noUnsafeOptionalChaining": "error", // 安全でないオプショナルチェーンでエラー
        "noUnusedVariables": "warn", // 未使用の変数でエラー
        "noVoidElementsWithChildren": "error", // childrenの無い要素に入れるとエラー
        "noVoidTypeReturn": "error", // 返り値がvoid型の関数が、returnするとエラー
        "useIsNan": "error", // NaNを比較するとエラー
        "useValidForDirection": "error" // forループで、終了しない条件だとエラー
      },
      "performance": {
        "noDelete": "error" // delete演算子使うとエラー
      },
      "security": {
        "noDangerouslySetInnerHtml": "warn" // dangerouslySetInnerHTML禁止
      },
      "style": {
        "noArguments": "error", // 定義してない変数使うとエラー
        "noNegationElse": "warn", // 条件で!fooのように書いてelseがあるとエラー
        "noNonNullAssertion": "warn", // foo!.varの書き方でエラー
        "noParameterAssign": "error", // 関数の引数を関数内で更新するとエラー
        "noUnusedTemplateLiteral": "error", // 普通の文字列でテンプレート文字列使うとエラー
        "noVar": "error", // var使うとエラー
        "useConst": "error", // letで再代入されないお変数はエラー、constにする
        "useExponentiationOperator": "error", // 階乗でMath.pow使うとエラー、**に置換
        "useNamingConvention": "off", // snakeCaseでエラー、optionで変えられる
        "useSelfClosingElements": "error", // <div></div>のように子供の無い要素でエラー、<div/>に置換
        "useShorthandArrayType": "error", // 型でArray使うとエラー、[]に置換
        "useTemplate": "error" // 文字の足し算は全てテンプレート文字列にする
      },
      "suspicious": {
        "noArrayIndexKey": "error", // JSXのmapでkeyにindexを渡すとエラー
        "noAssignInExpressions": "error", // 条件式に中で再代入するとエラー
        "noAsyncPromiseExecutor": "error", // new Promise()の中でasync関数使用するとエラー
        "noCatchAssign": "error", // catch(e)のeに再代入するとエラー
        "noClassAssign": "error", // classに再代入するとエラー
        "noCommentText": "error", // JSX内の正しくないコメントでエラー <div>// a</div> => <div>{/* a */}</div>
        "noCompareNegZero": "error", // -0と比較するとエラー
        "noConsoleLog": "warn", // console.logでエラー
        "noDoubleEquals": "error", // 比較で==を禁止、===にする
        "noDuplicateCase": "error", // switchの重複するcaseでエラー
        "noDuplicateClassMembers": "error", // classの重複するメソッドでエラー
        "noDuplicateJsxProps": "error", // コンポーネントの重複するPropsでエラー
        "noDuplicateObjectKeys": "error", // 重複するオブジェクトのkeyでエラー
        "noDuplicateParameters": "error", // 関数の重複するparamsでエラー
        "noEmptyInterface": "error", // 空のinterfaceの定義でエラー
        "noExplicitAny": "warn", // anyの仕様を禁止
        "noExtraNonNullAssertion": "error", // 間違った非nullアサーションでエラー
        "noFunctionAssign": "error", // functionの再代入するとエラー
        "noImportAssign": "error", // importで使う値を再代入するとエラー
        "noPrototypeBuiltins": "error", // エラーの恐れのあるオブジェクトのプロパティでエラー 例 propertyIsEnumerable, isPrototypeOf
        "noRedeclare": "error", // 同じ名前の宣言でエラー
        "noRedundantUseStrict": "error", // use strictが同じファイルで重複するとエラー
        "noSelfCompare": "error", // 同じ値の比較でエラー
        "noShadowRestrictedNames": "error", // 予約語で命名するとエラー
        "noUnsafeDeclarationMerging": "error", // 同じ名前のclassとinterfaceを定義するとエラー
        "useDefaultSwitchClauseLast": "error", // switchでdefaultが最後でないとエラー
        "useGetterReturn": "error", // classのgetメソッドでreturnをしないとエラー
        "useValidTypeof": "error" // typeofで比較する値が正しくないとエラー
      },
      "nursery": {
        "noDuplicateJsonKeys": "error", // JSONオブジェクトで同じkey使うとエラー
        "noEmptyCharacterClassInRegex": "error", // 正規化の[]の中が空だとエラー
        "noExcessiveComplexity": "warn", // 複雑なコード書くとエラー(階層が深くなる)
        "noGlobalIsFinite": "error", // isFiniteでは無く、Number.isFiniteを使う
        "noGlobalIsNan": "error", // isNaNでは無く、Number.isNaNを使う
        "noUselessElse": "warn", // 無駄なelseは早期リターンにする
        "useArrowFunction": "warn", // アロー関数を強制
        "useCollapsedElseIf": "warn", // elseの中の無駄な条件をelse ifに強制する
        "useExhaustiveDependencies": "warn", // useEffect等のHooksの依存配列が正しくないとエラー
        "useGroupedTypeImport": "error", // import {type A, type B}を、import type {A, B}に強制
        "useHookAtTopLevel": "error", // HooksはTopレベルで使わないとエラー
        "useIsArray": "error", // instanceof Arrayではなく、Array.isArray()を強制
        "useShorthandAssign": "error" // 短い書き方を強制 a = a + 1 => a += 1
      }
    }
  }
}

コメントなしver
biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.2.2/schema.json",
  "extends": [],
  "files": { "ignoreUnknown": true },
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "ignore": [],
    "indentSize": 2,
    "indentStyle": "space",
    "lineWidth": 80
  },
  "javascript": {
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    },
    "formatter": {
      "quoteStyle": "single",
      "jsxQuoteStyle": "single",
      "trailingComma": "all",
      "semicolons": "asNeeded",
      "arrowParentheses": "asNeeded"
    }
  },
  "json": {
    "parser": { "allowComments": true },
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentSize": 2,
      "lineWidth": 80
    }
  },
  "linter": {
    "ignore": [],
    "rules": {
      "a11y": {
        "noAriaUnsupportedElements": "error",
        "noBlankTarget": "error",
        "noDistractingElements": "error",
        "noNoninteractiveElementToInteractiveRole": "error",
        "noPositiveTabindex": "error",
        "noRedundantAlt": "error",
        "useAltText": "error",
        "useAriaPropsForRole": "error",
        "useHtmlLang": "error",
        "useIframeTitle": "error",
        "useMediaCaption": "error",
        "useValidAnchor": "error",
        "useValidAriaProps": "error",
        "useValidAriaValues": "error",
        "useValidLang": "error"
      },
      "complexity": {
        "noBannedTypes": "warn",
        "noExtraBooleanCast": "error",
        "noForEach": "warn",
        "noMultipleSpacesInRegularExpressionLiterals": "error",
        "noStaticOnlyClass": "error",
        "noUselessConstructor": "error",
        "noUselessRename": "error",
        "noUselessSwitchCase": "error",
        "useLiteralKeys": "error",
        "useOptionalChain": "error",
        "useSimplifiedLogicExpression": "error"
      },
      "correctness": {
        "noChildrenProp": "error",
        "noConstAssign": "error",
        "noConstantCondition": "error",
        "noEmptyPattern": "error",
        "noPrecisionLoss": "error",
        "noRenderReturnValue": "error",
        "noSelfAssign": "error",
        "noSetterReturn": "error",
        "noStringCaseMismatch": "error",
        "noUnnecessaryContinue": "error",
        "noUnreachable": "error",
        "noInvalidConstructorSuper": "error",
        "noUnsafeOptionalChaining": "error",
        "noUnusedVariables": "warn",
        "noVoidElementsWithChildren": "error",
        "noVoidTypeReturn": "error",
        "useIsNan": "error",
        "useValidForDirection": "error"
      },
      "performance": {
        "noDelete": "error"
      },
      "security": {
        "noDangerouslySetInnerHtml": "warn"
      },
      "style": {
        "noArguments": "error",
        "noNegationElse": "warn",
        "noNonNullAssertion": "warn",
        "noParameterAssign": "error",
        "noUnusedTemplateLiteral": "error",
        "noVar": "error",
        "useConst": "error",
        "useExponentiationOperator": "error",
        "useNamingConvention": "off",
        "useSelfClosingElements": "error",
        "useShorthandArrayType": "error",
        "useTemplate": "error"
      },
      "suspicious": {
        "noArrayIndexKey": "error",
        "noAssignInExpressions": "error",
        "noAsyncPromiseExecutor": "error",
        "noCatchAssign": "error",
        "noClassAssign": "error",
        "noCommentText": "error",
        "noCompareNegZero": "error",
        "noConsoleLog": "warn",
        "noDoubleEquals": "error",
        "noDuplicateCase": "error",
        "noDuplicateClassMembers": "error",
        "noDuplicateJsxProps": "error",
        "noDuplicateObjectKeys": "error",
        "noDuplicateParameters": "error",
        "noEmptyInterface": "error",
        "noExplicitAny": "warn",
        "noExtraNonNullAssertion": "error",
        "noFunctionAssign": "error",
        "noImportAssign": "error",
        "noPrototypeBuiltins": "error",
        "noRedeclare": "error",
        "noRedundantUseStrict": "error",
        "noSelfCompare": "error",
        "noShadowRestrictedNames": "error",
        "noUnsafeDeclarationMerging": "error",
        "useDefaultSwitchClauseLast": "error",
        "useGetterReturn": "error",
        "useValidTypeof": "error"
      },
      "nursery": {
        "noDuplicateJsonKeys": "error",
        "noEmptyCharacterClassInRegex": "error",
        "noExcessiveComplexity": "warn",
        "noGlobalIsFinite": "error",
        "noGlobalIsNan": "error",
        "noUselessElse": "warn",
        "useArrowFunction": "warn",
        "useCollapsedElseIf": "warn",
        "useExhaustiveDependencies": "warn",
        "useGroupedTypeImport": "error",
        "useHookAtTopLevel": "error",
        "useIsArray": "error",
        "useShorthandAssign": "error"
      }
    }
  }
}

所感

良いと思ったところ

  • 設定ファイルが1つにまとまるので見通しが良い
  • コードの実行速度がPrettier、ESLintよりも速い
  • formatterのルールがPrettier互換で取っつきやすい
  • lintのルールがある程度充実しているので、公式ドキュメントからプロジェクトに合うルールが探しやすい
  • pluginを入れずにルールを充実させられる
  • lintのルールが用途ごとに分類されていて探しやすい!
  • lintのルールのallrecommendedプロパティが便利!

改善して欲しいところ

  • フォーマッターがjs, ts, jsx, tsx, jsonのみのサポートなので、それ以外のファイルは別のフォーマッターが必要になる
  • Analyzerでのimportのソートが微妙。グループ化が出来ないので、現段階で他のツールに頼るしかないです。なので現段階だと足りないlintのルールだけESLintで補う、みたいになるのでしょうか...?
  • 実装されていないformatterやlintのルールを取り入れる方法が現段階で無い(pluginの導入出来るようになって欲しいです)

Biomeは導入が簡単なので、初学者やある程度の設定だけでならアリだと思います。
ですが、個人的にゴリゴリにルールを追加したいプロジェクトではまだ早いと感じました。
Biomeは絶賛開発中のため、これからもっと使いやすくなることに期待大です!

Discussion