ESLint+Prettier構成からESLint+Biomeのハイブリット構成に移行した話
はじめに
コードの品質管理ツールとして長らく ESLint+Prettier の構成が一般的だったが、近年 Biome という新しいツールが出てきた。Biome は高速なリンターとフォーマッターを兼ね備えたツールで、ESLint+Prettier の機能を統合することを目的にしている。
Biome の強みは以下の通り。
1. ツール統合によるメンテナンスコスト削減: lint, formatter をメンテする時は biome の設定ファイル を弄るだけで良くなる。
2. 高速な実行速度: 目に見えてわかるレベルでかなり早い。
ただ Biome はまだ発展途上であり、prettier に関しては 97%ほどカバーできているが、ESLint に関してはまだまだ対応できていないルールも多い。
この記事では、上司から Biome に移行するようタスクを任された筆者が、既存の ESLint+Prettier 構成から、Biome を活用したハイブリッド構成に移行した経験をまとめている。
渡されたタスクの内容
現状コードの品質管理ツールとして eslint と prettier を使用している。これを biome に移行したい。
ただ、biome はまだ発展途上のツールであり、eslint のプラグインなど細かいケースに対応しきれていない。
上記を踏まえた上でのタスクのゴールとしては、biome を適用可能な範囲で適用すること。
- prettier
コードの見た目しか役割がないので元の設定をなるべく維持しつつ完全に移行する - eslint
- Next.js のプラグインなど、biome が対応しきれていないプラグインについては eslint を残す
- 上記以外で現状 eslint でチェックしているルールを全て列挙し、biome が対応済みなものは全て移行する
- 残りの基本的なルールのうち biome が対応しきれていないものについては対応を考えるので未対応の状態で PR を作成し、説明文にリストアップする
biome の導入を行ったら、biome によるフォーマットをかけた上で PR を提出。
タスクの進め方
まずは渡されたタスクを実際にどのような手順で進めていくか分解した。全体を 5 つのステップに分けている。
1. 事前調査・準備
まずは現状把握と環境準備から始める。
-
biome の基本的な情報をキャッチアップ
- 公式ドキュメントや導入事例のブログ記事などを確認し、biome がどのようなルールセット・プラグインに対応しているのかを把握する。
- 他のリポジトリ含め、参考にした記事・ドキュメントの URL をメモしておく(後ほど PR にリストアップするため)。
-
ローカル環境の整備
- 今回の場合は、既存のリポジトリが最新の flatcofig 形式に対応していなかったため、まず eslint ルールの最新化を行う。
- 開発環境に biome をインストールしてテスト実行できるようにセットアップを行う。
- 可能であれば、Node.js のバージョンや他ツールのバージョンとの相性も確認しておく(利用する Next.js やプラグインのバージョンなど)。
2. ESLint ルールの洗い出し・分類
次に、現在使用している ESLint ルールを分析する。
-
現在使用している ESLint ルールの一覧化
- package.json で script の lint コマンドが対象としている tsx ファイルに対して、どのルールが有効になっているかを明確にする。
-
biome が対応しているルールの特定
- biome のドキュメントやリリースノートを照らし合わせながら、ESLint で使用しているルールが biome のどの機能(Lint/Format)で賄えるかを確認する。
- ルールごとに以下のようにステータスを振り分ける。
-
対応済み
: biome で同等のルールがある(オプションも含めて可能な限り近い設定にできる)。 -
未対応
: biome ではまだサポートされていない、あるいは Next.js プラグインなど特有のもの。 - 未対応の物は更に recommended なルールなのかどうかを調査する。
-
3. prettier から biome への移行設計
完全に移行する予定の prettier から移行する。
-
prettier と biome
- prettier は biome で 97%対応済みなので、完全に移行する
- これまでの prettier 設定(行の長さ・セミコロン有無・クォートルールなど)を確認し、biome の設定ファイル(
biome.json
)で同等になるよう設定する。
-
移行テスト
- 適当なブランチで biome に置き換えた場合のフォーマット実行(
biome format
)を試し、現在の prettier との差分が大きくないか・問題ないかを確認する。 - 設定の微調整が必要であればこの段階で調整し、既存フォーマットにできるだけ近づける。
- 適当なブランチで biome に置き換えた場合のフォーマット実行(
4. ESLint のルールを biome に置き換え
リンターを移行していく。
-
biome でカバーできるルールを ESLint 設定から削除する
- ステータスが「対応済み」のルールを ESLint 側から段階的に削除し、biome 側でオンにする設定を追加していく。
- inspired なルールに置き換える場合は、
eslint
を実行してエラーが発生すれば適宜ファイルの修正を行う。
-
Next.js プラグインなど「未対応」ルールの取り扱い
- 今回は「ESLint を残す」方針なので、
eslint.config.js
に「残すプラグイン」だけを明示的に設定し、biome と併用する形にする。 - 残っているルールの一覧は、PR に添えるドキュメントやコメント等で明確にしておく。
- 今回は「ESLint を残す」方針なので、
-
要調査/未対応 ルールのリストアップ
- まだ biome が追いついていないルールは、別途「未対応リスト」として PR やドキュメントに明示的に記載する。
5. 最終調整・PR 作成
最後に全体の調整と仕上げ。
-
biome 導入後のフォーマット, リント実行
-
biome format
,biome lint
を実行し、プロジェクト全体のコードスタイルを再度適用する。 - 変更差分を確認し、大量のリファクタリングが発生していないかをチェック。大きな差分が出てしまう場合は、設定を再調整するか、一時的に除外設定を入れるなど対応を検討する。
-
- その他諸々調整する
タスク
前述した計画に基づいて、実際に各ステップを実施していった。以下は実際の作業内容と結果である。
1. 事前調査・準備
-
biome の基本的な情報をキャッチアップ
[1], [8]を元に対応ルールを整理していく
-
ローカル環境の整備
- eslint ルールの最新化を行った。
- flatconfig に対応+不要なモジュールを削除したり、バージョンを上げたりが主。
2. ESLint ルールの洗い出し・分類
-
現在使用している ESLint ルールの一覧化
npx eslint --print-config page.tsx > eslint-config-output.json
で適用されている ESLint ルールを出力し、どのモジュール由来のルールかで分類、及び 1(warn), 2(error)のルールのみを残した(0 は off) -
biome が対応しているルールの特定
`@next/eslint-plugin-next`
@next/eslint-plugin-next のルール | Biome の対応状況 | Biome ルール名 |
---|---|---|
@next/next/google-font-display |
対応 | useGoogleFontDisplay |
@next/next/no-document-import-in-page |
対応 | noDocumentImportInPage |
@next/next/no-head-element |
対応 | noHeadElement |
@next/next/no-head-import-in-document |
対応 | noHeadImportInDocument |
@next/next/no-img-element |
対応 | noImgElement |
@next/next/google-font-preconnect |
未対応 | - |
@next/next/inline-script-id |
未対応 | - |
@next/next/next-script-for-ga |
未対応 | - |
@next/next/no-assign-module-variable |
未対応 | - |
@next/next/no-async-client-component |
未対応 | - |
@next/next/no-before-interactive-script-outside-document |
未対応 | - |
@next/next/no-css-tags |
未対応 | - |
@next/next/no-duplicate-head |
未対応 | - |
@next/next/no-html-link-for-pages |
未対応 | - |
@next/next/no-page-custom-font |
未対応 | - |
@next/next/no-script-component-in-head |
未対応 | - |
@next/next/no-styled-jsx-in-document |
未対応 | - |
@next/next/no-sync-scripts |
未対応 | - |
@next/next/no-title-in-document-head |
未対応 | - |
@next/next/no-typos |
未対応 | - |
@next/next/no-unwanted-polyfillio |
未対応 | - |
`@typescript-eslint`
@typescript-eslint のルール | Biome の対応状況 | Biome ルール名 | recommended |
---|---|---|---|
@typescript-eslint/array-type |
対応 | useConsistentArrayType |
|
@typescript-eslint/ban-ts-comment |
未対応 | - | yes |
@typescript-eslint/consistent-type-imports |
対応 |
useImportType (inspired) |
|
@typescript-eslint/no-array-constructor |
対応 | useArrayLiterals |
|
@typescript-eslint/no-duplicate-enum-values |
未対応 | - | yes |
@typescript-eslint/no-dynamic-delete |
未対応 | - | no |
@typescript-eslint/no-empty-object-type |
未対応 | - | yes |
@typescript-eslint/no-explicit-any |
対応 | noExplicitAny |
|
@typescript-eslint/no-extra-non-null-assertion |
対応 | noExtraNonNullAssertion |
|
@typescript-eslint/no-extraneous-class |
対応 | noStaticOnlyClass |
|
@typescript-eslint/no-invalid-void-type |
対応 | noConfusingVoidType |
|
@typescript-eslint/no-misused-new |
対応 | noMisleadingInstantiator |
|
@typescript-eslint/no-namespace |
対応 | noNamespace |
|
@typescript-eslint/no-non-null-asserted-nullish-coalescing |
未対応 | - | no |
@typescript-eslint/no-non-null-asserted-optional-chain |
未対応 | - | yes |
@typescript-eslint/no-non-null-assertion |
対応 | noNonNullAssertion |
|
@typescript-eslint/no-require-imports |
対応 | noCommonJs |
|
@typescript-eslint/no-this-alias |
対応 |
noUselessThisAlias (inspired) |
|
@typescript-eslint/no-unnecessary-type-constraint |
対応 | noUselessTypeConstraint |
|
@typescript-eslint/no-unsafe-declaration-merging |
対応 | noUnsafeDeclarationMerging |
|
@typescript-eslint/no-unsafe-function-type |
未対応 | - | yes |
@typescript-eslint/no-unused-expressions |
未対応 | - | yes |
@typescript-eslint/no-unused-vars |
対応 | noUnusedVariables |
|
@typescript-eslint/no-useless-constructor |
対応 | noUselessConstructor |
|
@typescript-eslint/no-wrapper-object-types |
未対応 | - | yes |
@typescript-eslint/prefer-as-const |
対応 | useAsConstAssertion |
|
@typescript-eslint/prefer-literal-enum-member |
対応 | useLiteralEnumMembers |
|
@typescript-eslint/prefer-namespace-keyword |
対応 | useNamespaceKeyword |
|
@typescript-eslint/triple-slash-reference |
未対応 | - | yes |
@typescript-eslint/unified-signatures |
未対応 | - | no |
`eslint`
ESLint のルール | Biome の対応状況 | Biome ルール名 | recommended? |
---|---|---|---|
arrow-body-style |
未対応 | - | no |
camelcase |
未対応 | - | no |
consistent-return |
未対応 | - | no |
default-case |
対応 | useDefaultSwitchClause |
|
default-case-last |
対応 | useDefaultSwitchClauseLast |
|
default-param-last |
対応 | useDefaultParameterLast |
|
dot-notation |
対応 | useLiteralKeys |
|
eqeqeq |
対応 | noDoubleEquals |
|
for-direction |
対応 | useValidForDirection |
|
global-require |
未対応 | - | deprecated |
grouped-accessor-pairs |
未対応 | - | no |
guard-for-in |
対応 | useGuardForIn |
|
lines-around-directive |
未対応 | - | deprecated |
lines-between-class-members |
未対応 | - | deprecated |
max-classes-per-file |
未対応 | - | no |
no-async-promise-executor |
対応 | noAsyncPromiseExecutor |
|
no-await-in-loop |
未対応 | - | no |
no-caller |
未対応 | - | no |
no-case-declarations |
対応 | noSwitchDeclarations |
|
no-compare-neg-zero |
対応 | noCompareNegZero |
|
no-cond-assign |
対応 |
noAssignInExpressions (inspired) |
|
no-console |
対応 | noConsole |
|
no-constant-binary-expression |
未対応 | - | yes |
no-constant-condition |
対応 | noConstantCondition |
|
no-constructor-return |
対応 | noConstructorReturn |
|
no-continue |
未対応 | - | no |
no-control-regex |
対応 | noControlCharactersInRegex |
|
no-debugger |
対応 | noDebugger |
|
no-delete-var |
未対応 | - | yes |
no-dupe-else-if |
対応 | noDuplicateElseIf |
|
no-duplicate-case |
対応 | noDuplicateCase |
|
no-else-return |
対応 |
noUselessElse (inspired) |
|
no-empty |
対応 | noEmptyBlockStatements |
|
no-empty-character-class |
対応 | noEmptyCharacterClassInRegex |
|
no-empty-pattern |
対応 | noEmptyPattern |
|
no-empty-static-block |
対応 | noEmptyBlockStatements |
|
no-eval |
対応 | noGlobalEval |
|
no-ex-assign |
対応 | noCatchAssign |
|
no-extend-native |
未対応 | - | no |
no-extra-bind |
未対応 | - | no |
no-extra-boolean-cast |
対応 | noExtraBooleanCast |
|
no-extra-label |
対応 | noUselessLabel |
|
no-fallthrough |
対応 | noFallthroughSwitchClause |
|
no-global-assign |
対応 | noGlobalAssign |
|
no-invalid-regexp |
未対応 | - | yes |
no-irregular-whitespace |
対応 | noIrregularWhitespace |
|
no-iterator |
未対応 | - | no |
no-lonely-if |
対応 | useCollapsedElseIf |
|
no-loop-func |
未対応 | - | no |
no-loss-of-precision |
対応 | noPrecisionLoss |
|
no-misleading-character-class |
対応 | noMisleadingCharacterClass |
|
no-multi-assign |
未対応 | - | no |
no-multi-str |
未対応 | - | no |
no-nested-ternary |
対応 | noNestedTernary |
|
no-new |
未対応 | - | no |
no-new-func |
未対応 | - | no |
no-new-object |
対応 | useConsistentBuiltinInstantiation |
|
no-new-wrappers |
対応 | useConsistentBuiltinInstantiation |
|
no-nonoctal-decimal-escape |
対応 | noNonoctalDecimalEscape |
|
no-octal |
未対応 | - | yes |
no-octal-escape |
対応 | noOctalEscape |
|
no-param-reassign |
対応 | noParameterAssign |
|
no-path-concat |
未対応 | - | deprecated |
no-proto |
未対応 | - | no |
no-prototype-builtins |
対応 | noPrototypeBuiltins |
|
no-regex-spaces |
対応 | noMultipleSpacesInRegularExpressionLiterals |
|
no-restricted-exports |
未対応 | - | no |
no-return-assign |
未対応 | - | no |
no-return-await |
未対応 | - | deprecated |
no-self-assign |
対応 | noSelfAssign |
|
no-self-compare |
対応 | noSelfCompare |
|
no-shadow |
未対応 | - | no |
no-shadow-restricted-names |
対応 | noShadowRestrictedNames |
|
no-sparse-arrays |
対応 | noSparseArray |
|
no-throw-literal |
対応 |
useThrowOnlyError (inspired) |
|
no-undef-init |
対応 | noUselessUndefinedInitialization |
|
no-unneeded-ternary |
対応 | noUselessTernary |
|
no-unsafe-optional-chaining |
対応 | noUnsafeOptionalChaining |
|
no-unused-labels |
対応 | noUnusedLabels |
|
no-unused-private-class-members |
対応 | noUnusedPrivateClassMembers |
|
no-use-before-define |
対応 | noInvalidUseBeforeDeclaration |
|
no-useless-catch |
対応 | noUselessCatch |
|
no-useless-concat |
対応 | noUselessStringConcat |
|
no-useless-constructor |
対応 | noUselessConstructor |
|
no-useless-escape |
対応 | noUselessEscapeInRegex |
|
no-var |
対応 | noVar |
|
prefer-arrow-callback |
対応 |
useArrowFunction (inspired) |
|
prefer-const |
対応 | useConst |
|
prefer-exponentiation-operator |
対応 | useExponentiationOperator |
|
prefer-regex-literals |
対応 | useRegexLiterals |
|
valid-typeof |
対応 | useValidTypeof |
`eslint-plugin-import`
ESLint import のルール |
Biome の対応状況 | Biome ルール名 |
---|---|---|
import/default |
未対応 | - |
import/export |
未対応 | - |
import/named |
未対応 | - |
import/namespace |
未対応 | - |
import/no-duplicates |
未対応 | - |
import/no-extraneous-dependencies |
対応 | noUndeclaredDependencies |
import/no-named-as-default |
未対応 | - |
import/no-named-as-default-member |
未対応 | - |
import/no-relative-packages |
未対応 | - |
import/no-unresolved |
未対応 | - |
import/prefer-default-export |
未対応 | - |
`eslint-plugin-jsx-a11y`
ESLint jsx-a11y のルール |
Biome の対応状況 | Biome ルール名 | recommended |
---|---|---|---|
jsx-a11y/alt-text |
対応 | useAltText |
|
jsx-a11y/anchor-has-content |
対応 | useAnchorContent |
|
jsx-a11y/anchor-is-valid |
対応 | useValidAnchor |
|
jsx-a11y/aria-activedescendant-has-tabindex |
対応 | useAriaActivedescendantWithTabindex |
|
jsx-a11y/aria-props |
対応 | useValidAriaProps |
|
jsx-a11y/aria-proptypes |
対応 | useValidAriaValues |
|
jsx-a11y/aria-role |
対応 | useValidAriaRole |
|
jsx-a11y/aria-unsupported-elements |
対応 | noAriaUnsupportedElements |
|
jsx-a11y/autocomplete-valid |
対応 | useValidAutocomplete |
|
jsx-a11y/click-events-have-key-events |
対応 | useKeyWithClickEvents |
|
jsx-a11y/heading-has-content |
対応 | useHeadingContent |
|
jsx-a11y/html-has-lang |
対応 | useHtmlLang |
|
jsx-a11y/iframe-has-title |
対応 | useIframeTitle |
|
jsx-a11y/img-redundant-alt |
対応 | noRedundantAlt |
|
jsx-a11y/interactive-supports-focus |
対応 | useFocusableInteractive |
|
jsx-a11y/label-has-associated-control |
対応 | noLabelWithoutControl |
|
jsx-a11y/media-has-caption |
対応 | useMediaCaption |
|
jsx-a11y/mouse-events-have-key-events |
対応 | useKeyWithMouseEvents |
|
~~jsx-a11y/no-access-key~~ |
対応 |
noAccessKey (inspired) |
|
jsx-a11y/no-autofocus |
対応 | noAutofocus |
|
jsx-a11y/no-distracting-elements |
対応 | noDistractingElements |
|
jsx-a11y/no-interactive-element-to-noninteractive-role |
対応 | noInteractiveElementToNoninteractiveRole |
|
jsx-a11y/no-noninteractive-element-interactions |
未対応 | - | yes |
jsx-a11y/no-noninteractive-element-to-interactive-role |
対応 | noNoninteractiveElementToInteractiveRole |
|
jsx-a11y/no-noninteractive-tabindex |
対応 | noNoninteractiveTabindex |
|
jsx-a11y/no-redundant-roles |
対応 | noRedundantRoles |
|
jsx-a11y/no-static-element-interactions |
対応 | noStaticElementInteractions |
|
jsx-a11y/role-has-required-aria-props |
対応 | useAriaPropsForRole |
|
jsx-a11y/role-supports-aria-props |
対応 | useAriaPropsSupportedByRole |
|
jsx-a11y/scope |
対応 | noHeaderScope |
|
jsx-a11y/tabindex-no-positive |
対応 | noPositiveTabindex |
`eslint-plugin-react`
ESLint react のルール |
Biome の対応状況 | Biome ルール名 | recommended? |
---|---|---|---|
react/button-has-type |
対応 | useButtonType |
|
react/jsx-boolean-value |
対応 |
noImplicitBoolean (inspired) |
|
react/jsx-curly-brace-presence |
対応 |
useConsistentCurlyBraces (inspired) |
|
react/jsx-fragments |
対応 | useFragmentSyntax |
|
react/jsx-key |
対応 | useJsxKeyInIterable |
|
react/jsx-no-comment-textnodes |
対応 | noCommentText |
|
react/jsx-no-duplicate-props |
対応 | noDuplicateJsxProps |
|
react/jsx-no-target-blank |
対応 | noBlankTarget |
|
react/jsx-no-useless-fragment |
対応 | noUselessFragments |
|
react/no-children-prop |
対応 | noChildrenProp |
|
react/no-danger-with-children |
対応 | noDangerouslySetInnerHtmlWithChildren |
|
react/self-closing-comp |
対応 | noVoidElementsWithChildren |
|
react/jsx-uses-vars |
対応 | noUnusedVariables |
yes |
react/display-name (古) |
未対応 | - | yes |
react/function-component-definition (古) |
未対応 | - | no |
react/hook-use-state (古) |
未対応 | - | no |
react/jsx-no-constructed-context-values (古) |
未対応 | - | no |
react/jsx-pascal-case (古) |
未対応 | - | no |
react/no-deprecated (古) |
未対応 | - | yes |
react/no-direct-mutation-state (古) |
未対応 | - | yes |
react/no-find-dom-node (古) |
未対応 | - | yes |
react/no-is-mounted (古) |
未対応 | - | yes |
react/no-render-return-value (古) |
未対応 | - | yes |
react/no-string-refs (古) |
未対応 | - | yes |
react/no-unescaped-entities (古) |
未対応 | - | yes |
react/no-unknown-property (古) |
未対応 | - | yes |
react/require-render-return (古) |
未対応 | - | yes |
`eslint-plugin-react-hooks`
ESLint react-hooks のルール |
Biome の対応状況 | Biome ルール名 |
---|---|---|
react-hooks/exhaustive-deps |
対応 |
useExhaustiveDependencies (inspired) |
react-hooks/rules-of-hooks |
対応 | useHookAtTopLevel |
`eslint-plugin-tailwindcss`
未対応
3. prettier から biome への移行設計
-
prettier と biome
-
pnpm add --save-dev --save-exact @biomejs/biome
-
pnpm biome init
で biome.json を出力 -
biome.json を編集
package.json script を参考に、formatter が対象とする拡張子を以下のように設定した。
javascript に書かれた設定は javascipt ファイルと typescript ファイルに適用される[2]
{ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, "files": { "ignoreUnknown": false, "ignore": [".next/"] }, "formatter": { "enabled": true, "lineWidth": 120, "indentStyle": "space", "indentWidth": 2 }, "organizeImports": { "enabled": true }, "linter": { "enabled": true, "rules": { "recommended": true } }, "javascript": { "formatter": { "quoteStyle": "single", "trailingCommas": "all" } }, "json": { "formatter": { "enabled": false } } }
-
package.json の編集
元の format コマンドを biome に置き換えた
"scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "eslint . --max-warnings 0", "lint:fix": "eslint . --fix", "format": "biome format --write .", "format-check": "biome check .", "type-check": "tsc --noEmit" },
-
-
移行テスト
- pnpm format を実行した
- prettier より不要な改行に厳しいっぽい?
- また、javascript を対象にしているため、mjs ファイルも引っかかってしまうが誤差の範囲内と考えた
- pnpm format-check は linter も含まれているため、この段階で実行してもエラーが出る
- pnpm format を実行した
4. ESLint のルールを biome に置き換え
-
biome でカバーできるルールを ESLint 設定から切り出す or 無効化
- eslint でエラーが出ない状態で、biome.json にエラー 0 を保ちながらルールを追加していく
- eslint.config.js でいらない package を削除
-
Next.js プラグインなど「未対応」ルールの取り扱い
- 残すべき
-
eslint-plugin-tailwindcss
:完全に未対応 -
@next/eslint-plugin-next
:まだまだ発展途上 -
eslint-plugin-import
:ほぼ完全に未対応
-
- 残した方が良い
-
@typescript-eslint
- Biome では TypeScript の型情報を扱うことができないので、型情報が必要なルールについては基本的にサポートしていないとのこと[8]
- し、そこそこ recommended ルール漏れてる
-
consistent-type-imports
と対応しているuseImportType
に関しては inspired なので若干挙動が違うっぽく、一旦 off にしている - +@toyokumo/eslint-config から
eslint-plugin-import
と抱き合わせで入れているので、消したくない
-
- 残すべき
-
要調査/未対応 ルールのリストアップ
- 消すべき
-
eslint-plugin-react-hooks
:全部対応できている
-
- 消した方が良い
-
eslint-plugin-jsx-a11y
: 1 つしか未対応ルールがない -
eslint
: recommended に絞れば相当対応できている -
eslint-plugin-react
: (古いルールを除外すれば)未対応はなし
※[8]曰く、 recommended ルールの中には、hooks が登場する以前のクラスコンポーネントなどに関連する古いルールも多く含まれているとのこと。
-
以上を踏まえて、
eslint-plugin-jsx-a11y
,eslint-plugin-react
,eslint
は eslint.config.js から削除済み。未対応のルールは以下の通り。
- 消すべき
`eslint-plugin-jsx-a11y`
ルール | recommended? |
---|---|
jsx-a11y/no-noninteractive-element-interactions |
yes |
`eslint-plugin-react`
ルール | recommended? |
---|---|
react/display-name (古) |
yes |
react/function-component-definition (古) |
no |
react/hook-use-state (古) |
no |
react/jsx-no-constructed-context-values (古) |
no |
react/jsx-pascal-case (古) |
no |
react/no-deprecated (古) |
yes |
react/no-direct-mutation-state (古) |
yes |
react/no-find-dom-node (古) |
yes |
react/no-is-mounted (古) |
yes |
react/no-render-return-value (古) |
yes |
react/no-string-refs (古) |
yes |
react/no-unescaped-entities (古) |
yes |
react/no-unknown-property (古) |
yes |
react/require-render-return (古) |
yes |
`eslint`
ESLint のルール | recommended? |
---|---|
arrow-body-style |
no |
camelcase |
no |
consistent-return |
no |
global-require |
deprecated |
grouped-accessor-pairs |
no |
lines-around-directive |
deprecated |
lines-between-class-members |
deprecated |
max-classes-per-file |
no |
no-await-in-loop |
no |
no-caller |
no |
no-constant-binary-expression |
yes |
no-continue |
no |
no-delete-var |
yes |
no-extend-native |
no |
no-extra-bind |
no |
no-invalid-regexp |
yes |
no-iterator |
no |
no-loop-func |
no |
no-multi-assign |
no |
no-multi-str |
no |
no-new |
no |
no-new-func |
no |
no-octal |
yes |
no-path-concat |
deprecated |
no-proto |
no |
no-restricted-exports |
no |
no-return-assign |
no |
no-return-await |
deprecated |
no-shadow |
no |
- recommended に絞れば相当対応できている
- 尚、
no-var
ルールに対応しているnoVar
に関しては、「プロパティ noVar は許可されていません。」という warn が出るため一旦書いていない
5. 最終調整・PR 作成
- biome 導入後のフォーマット実行
- その他諸々調整
-
CICD ファイルの一部フローの name を変更
-
不要になった Prettier の設定ファイルを削除
-
settings.json と extensions.json の設定ファイルを変更(こちらに関してはまだやっていない)
[10]を参考に。"recommendations": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "usernamehw.errorlens", "formulahendry.auto-close-tag", "formulahendry.auto-rename-tag", "bradlc.vscode-tailwindcss" ], から "recommendations": [ "dbaeumer.vscode-eslint", "biomejs.biome", //拡張機能のレコメンド "usernamehw.errorlens", "formulahendry.auto-close-tag", "formulahendry.auto-rename-tag", "bradlc.vscode-tailwindcss" ],
"editor.defaultFormatter": "biomejs.biome", "[javascript]": { "editor.defaultFormatter": "biomejs.biome" }, "[javascriptreact]": { "editor.defaultFormatter": "biomejs.biome" }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome" }, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" }
参考文献
公式ページに載っているルール定義
[1] Biome 公式, Rules Sources
[2] Biome 公式, Configuration
[3] eslint 公式, Rules References
[4] github, typescript-eslint recommended
[5] github, typescript-eslint recommended-type-checked
[6] github, eslint-plugin-jsx-a11y supported rules
[7] github, eslint-plugin-react supported rules
導入事例
[8] zenn, Biome と ESLint の lint ルールの互換性
[9] zenn, 【Next.js】Biome と ESLint のハイブリッド構成について考える(暫定版)
[10] zenn, フォーマッターとリンターを兼ね備えた「Biome」を触ってみる
Discussion