ESLint + Prettier から Biome に移行したら動かない
Biome は 2024 年に v1.0 がリリースされた高速な Linter/Formatter で、ESLint + Prettier の代替として注目されています。しかし実際に移行してみると「ルールが全然効かない」「VS Code で自動フォーマットされない」「CI が落ちる」といった問題に直面することが多いです。
よく見るエラー:
$ biome check .
error[migrate]: Rule "no-explicit-any" is not supported. Use "typescript/noExplicitAny" instead.
$ npx biome format --write .
error: Failed to parse configuration from biome.json
× Unexpected value `tab` at `formatter.indentStyle`
この記事では移行時にハマりやすい 5 つの原因と対策を解説します。
前提:Biome の基本セットアップ
npm install --save-dev --save-exact @biomejs/biome
npx @biomejs/biome init
これで biome.json が生成されます。
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
}
}
原因1:VS Code 拡張が ESLint/Prettier のままで Biome 拡張が未インストール
「biome check コマンドは通るのに、VS Code でエラーが表示されない・保存しても自動フォーマットされない」というケース。
原因は VS Code の拡張機能設定です。ESLint や Prettier の拡張機能をそのまま使っていて、Biome の拡張機能がインストールされていないため、エディタが Biome を認識できていません。
対策:
- VS Code に Biome 拡張機能(
biomejs.biome)をインストール .vscode/settings.jsonを更新する
{
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
重要: ESLint/Prettier の拡張機能を無効化するか、ワークスペースで無効にしましょう。両方有効だとコンフリクトして意図しない動作になります。
チームで共有する場合は .vscode/extensions.json も更新します。
{
"recommendations": ["biomejs.biome"],
"unwantedRecommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
}
原因2:package.json の scripts が ESLint/Prettier のまま
CI/CD で「biome を入れたはずなのに、npm run lint が ESLint を呼んでいる」ケース。
// ❌ NG: まだ ESLint/Prettier を呼んでいる
{
"scripts": {
"lint": "eslint . --ext .ts,.tsx",
"format": "prettier --write ."
}
}
CI 上では ESLint/Prettier がデフォルトで入っていないため、上記のままだと command not found エラーになります。
対策: scripts を Biome に切り替える。
// ✅ OK: Biome に切り替える
{
"scripts": {
"lint": "biome lint .",
"format": "biome format --write .",
"check": "biome check .",
"check:ci": "biome ci ."
}
}
ポイントは CI では biome ci を使うことです。biome check と異なり、biome ci はファイルを書き換えず、差分があった場合に非ゼロ終了コードを返します。biome check を CI で使うとフォーマット差分があっても終了コード 0 になってしまうことがあります。
# .github/workflows/ci.yml
- name: Lint and format check
run: npx biome ci .
原因3:型を使う ESLint ルールが Biome で動かない
「@typescript-eslint/no-floating-promises や @typescript-eslint/await-thenable などのルールが移行後に消えた」というケース。
これは仕様です。 Biome v1.x は現時点で TypeScript の型情報を参照するルールをサポートしていません。
型チェックが必要なため Biome に存在しないルールの例:
@typescript-eslint/no-floating-promises@typescript-eslint/await-thenable@typescript-eslint/no-misused-promises@typescript-eslint/restrict-template-expressions@typescript-eslint/no-unsafe-assignment
対策: 型チェックが必要なルールのみ ESLint を残す「ハイブリッド構成」にする。
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
// eslint.config.mjs (最小構成:型チェックルールのみ)
import tseslint from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
export default [
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: tsParser,
parserOptions: {
project: './tsconfig.json',
},
},
plugins: { '@typescript-eslint': tseslint },
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': 'error',
},
},
]
// package.json scripts(ハイブリッド構成)
{
"scripts": {
"lint": "biome lint . && eslint .",
"format": "biome format --write .",
"check:ci": "biome ci . && eslint ."
}
}
型チェックルールの実行は遅いため、biome lint で高速チェック → eslint で型チェックという順番が効率的です。
原因4:husky / lint-staged の設定が ESLint/Prettier のまま
「コミット時のプリコミットフックで eslint: command not found になる」ケース。
// ❌ NG: lint-staged が ESLint/Prettier のまま
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md}": ["prettier --write"]
}
}
対策: lint-staged の設定を Biome に切り替える。
// ✅ OK: Biome に切り替える
{
"lint-staged": {
"*.{js,ts,jsx,tsx,json}": [
"biome check --apply --no-errors-on-unmatched --files-ignore-unknown=true"
]
}
}
--no-errors-on-unmatched をつけないと、lint-staged が渡すファイルパスが Biome の対象外(例:.md ファイル)だった場合にエラーになります。--files-ignore-unknown=true も合わせて指定することで、未対応ファイルを無視できます。
原因5:biome.json のルール名が ESLint と命名規則が違う
「ESLint のルール名をそのまま biome.json に書いてもエラーになる」ケース。
// ❌ NG: ESLint の命名規則(kebab-case)をそのまま使っている
{
"linter": {
"rules": {
"no-explicit-any": "error",
"no-unused-vars": "warn"
}
}
}
error: Unknown rule "no-explicit-any". Did you mean "typescript/noExplicitAny"?
Biome のルール名は ESLint と命名規則が異なります。ESLint は kebab-case、Biome は カテゴリ/camelCase の形式です。
対策: Biome のルール名に変換する。
// ✅ OK: Biome の形式で記述
{
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"typescript": {
"noExplicitAny": "error"
},
"correctness": {
"noUnusedVariables": "warn"
},
"suspicious": {
"noConsoleLog": "warn",
"noDoubleEquals": "error"
},
"style": {
"useConst": "error",
"noVar": "error"
}
}
}
}
よく使う ESLint ルールと Biome ルールの対応表:
| ESLint ルール | Biome ルール |
|---|---|
@typescript-eslint/no-explicit-any |
typescript/noExplicitAny |
no-unused-vars |
correctness/noUnusedVariables |
no-console |
suspicious/noConsoleLog |
eqeqeq |
suspicious/noDoubleEquals |
prefer-const |
style/useConst |
no-var |
style/noVar |
no-debugger |
suspicious/noDebugger |
no-alert |
suspicious/noAlert |
全対応表は Biome 公式の Rules Sources ページで確認できます。
まとめ
Biome への移行でよくあるハマりポイントをまとめます。
| 症状 | 原因 | 対策 |
|---|---|---|
| VS Code で動かない | Biome 拡張未インストール | 拡張インストール + .vscode/settings.json 設定 |
| CI で lint が通らない | scripts が ESLint のまま | biome ci . に切り替え |
| 型チェックルールが消えた | Biome が型情報非対応 | ESLint とのハイブリッド構成 |
| コミット時フックが失敗 | lint-staged が古い設定 | biome check --apply に更新 |
| ルール設定がエラーになる | ルール名の命名規則が違う | camelCase の Biome 形式に変換 |
Biome は ESLint/Prettier より大幅に高速(10〜100 倍)で、設定ファイルも biome.json 1 つで完結します。型チェックルールのみ ESLint をハイブリッドで残せば、ほとんどのプロジェクトで実用的な構成が組めます。ぜひ移行を試してみてください。
