Biome統合フォーマッター・リンター完全ガイド - Prettier/ESLintからの移行と高速化


Biomeは、PrettierとESLintを統合した次世代のツールチェーンです。Rustで書かれており、従来のツールと比べて最大100倍高速に動作します。2024年にv1.0がリリースされ、本番環境での使用が推奨されるレベルに到達しました。

この記事では、Biomeの導入から既存プロジェクトの移行、CI/CD統合、チーム開発での運用まで実践的に解説します。

Biomeとは何か

従来のツールチェーンの課題

// ❌ 従来: 複数ツールの設定ファイル
// .prettierrc.json
{
  "semi": false,
  "singleQuote": true
}

// .eslintrc.json
{
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
  "plugins": ["@typescript-eslint", "import", "react-hooks"],
  "rules": { ... }
}

// .editorconfig
// tsconfig.json
// ...

// 問題点:
// - 設定ファイルが分散
// - node_modulesが肥大化(200MB+)
// - 実行速度が遅い(大規模プロジェクトで数十秒)
// - ツール間の競合

Biomeによる統一

// ✅ Biome: 1つの設定ファイル
// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.5.0/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded"
    }
  }
}

// 利点:
// - 単一バイナリ(10MB程度)
// - 超高速(Rustネイティブ)
// - 設定が集約
// - フォーマット・リントが統合

インストールとセットアップ

新規プロジェクト

# Biomeインストール
npm install --save-dev --save-exact @biomejs/biome

# または
pnpm add -D -E @biomejs/biome
yarn add -D -E @biomejs/biome

# 初期化
npx @biomejs/biome init

package.jsonスクリプト

{
  "scripts": {
    "lint": "biome lint .",
    "format": "biome format --write .",
    "check": "biome check --write .",
    "ci": "biome ci ."
  }
}

基本的な設定ファイル

// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.5.0/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noExplicitAny": "warn"
      },
      "complexity": {
        "noForEach": "off"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingComma": "es5",
      "semicolons": "asNeeded",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false
    }
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": [
      "node_modules",
      "dist",
      "build",
      ".next",
      "coverage"
    ]
  }
}

Prettier/ESLintからの移行

移行前のチェック

# 現在の設定を確認
cat .prettierrc.json .eslintrc.json

# Biome移行ヘルパー使用
npx @biomejs/biome migrate --write

Prettier設定の移行

// .prettierrc.json → biome.json

// Before (Prettier)
{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "es5",
  "bracketSpacing": true,
  "bracketSameLine": false,
  "arrowParens": "always"
}

// After (Biome)
{
  "formatter": {
    "lineWidth": 100,
    "indentWidth": 2,
    "indentStyle": "space"
  },
  "javascript": {
    "formatter": {
      "semicolons": "asNeeded",
      "quoteStyle": "single",
      "quoteProperties": "asNeeded",
      "jsxQuoteStyle": "double",
      "trailingComma": "es5",
      "bracketSpacing": true,
      "bracketSameLine": false,
      "arrowParentheses": "always"
    }
  }
}

ESLint設定の移行

// .eslintrc.json → biome.json

// Before (ESLint)
{
  "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
  "rules": {
    "no-console": "warn",
    "no-unused-vars": "error",
    "@typescript-eslint/no-explicit-any": "warn"
  }
}

// After (Biome)
{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noConsoleLog": "warn",
        "noExplicitAny": "warn"
      },
      "correctness": {
        "noUnusedVariables": "error"
      }
    }
  }
}

段階的移行戦略

# ステップ1: Biomeインストール(既存ツールは残す)
pnpm add -D @biomejs/biome

# ステップ2: 並行運用期間
# package.json
{
  "scripts": {
    "lint:old": "eslint .",
    "lint:new": "biome lint .",
    "format:old": "prettier --write .",
    "format:new": "biome format --write ."
  }
}

# ステップ3: 差分確認
npm run format:old
npm run format:new
git diff  # 差分がほぼないことを確認

# ステップ4: 古いツール削除
pnpm remove eslint prettier @typescript-eslint/eslint-plugin # ...
rm .eslintrc.json .prettierrc.json

# ステップ5: Biomeに統一
{
  "scripts": {
    "lint": "biome lint .",
    "format": "biome format --write .",
    "check": "biome check --write ."
  }
}

VSCode統合

拡張機能インストール

// .vscode/extensions.json
{
  "recommendations": [
    "biomejs.biome"
  ],
  "unwantedRecommendations": [
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint"
  ]
}

VSCode設定

// .vscode/settings.json
{
  // Biomeを有効化
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },

  // 特定言語でのみ有効化
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

  // Prettier/ESLintを無効化
  "prettier.enable": false,
  "eslint.enable": false
}

ワークスペース推奨設定

// .vscode/settings.json(チーム共有用)
{
  "files.associations": {
    "*.css": "css",
    "*.json": "jsonc"
  },
  "biome.lspBin": "./node_modules/@biomejs/biome/bin/biome",
  "editor.defaultFormatter": "biomejs.biome",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  }
}

リンタールール詳細設定

カテゴリ別ルール設定

{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,

      // A11y(アクセシビリティ)
      "a11y": {
        "noSvgWithoutTitle": "error",
        "useAltText": "error",
        "useButtonType": "warn"
      },

      // 複雑さ
      "complexity": {
        "noBannedTypes": "error",
        "noUselessTypeConstraint": "error",
        "noExtraBooleanCast": "error",
        "noForEach": "off"  // forEachを許可
      },

      // 正確性
      "correctness": {
        "noUnusedVariables": "error",
        "noUndeclaredVariables": "error",
        "useExhaustiveDependencies": "warn"  // React hooksの依存配列
      },

      // セキュリティ
      "security": {
        "noDangerouslySetInnerHtml": "warn"
      },

      // スタイル
      "style": {
        "noNonNullAssertion": "off",  // TypeScriptの ! 許可
        "useImportType": "error",     // import type強制
        "useConst": "error",
        "noVar": "error"
      },

      // 疑わしいコード
      "suspicious": {
        "noExplicitAny": "warn",
        "noArrayIndexKey": "warn",  // React key={index} 警告
        "noConsoleLog": "warn",
        "noDebugger": "error"
      }
    }
  }
}

ファイル・パスごとのオーバーライド

{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "overrides": [
    {
      "include": ["**/*.test.ts", "**/*.spec.ts"],
      "linter": {
        "rules": {
          "suspicious": {
            "noExplicitAny": "off"  // テストではanyを許可
          }
        }
      }
    },
    {
      "include": ["scripts/**/*.js"],
      "linter": {
        "rules": {
          "suspicious": {
            "noConsoleLog": "off"  // スクリプトではconsole.log許可
          }
        }
      }
    },
    {
      "include": ["src/**/*.tsx"],
      "formatter": {
        "lineWidth": 120  // React JSXは行長を緩和
      }
    }
  ]
}

コマンドラインの使い方

フォーマット

# チェックのみ(変更なし)
biome format .

# 修正を適用
biome format --write .

# 特定ファイルのみ
biome format --write src/index.ts

# 標準入力からフォーマット
echo "const x={a:1}" | biome format --stdin-file-path=test.js

リント

# リントチェック
biome lint .

# 自動修正適用
biome lint --write .

# 特定ルールのみ適用
biome lint --only=suspicious/noConsoleLog .

# 診断レベル指定
biome lint --diagnostic-level=warn .

統合コマンド(check)

# フォーマット + リント + インポート整理を一括実行
biome check --write .

# CIモード(修正なし、エラーで終了)
biome ci .

# 変更されたファイルのみチェック
git diff --name-only --diff-filter=ACMR | xargs biome check --write

CI/CD統合

GitHub Actions

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v2
        with:
          version: 8

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Run Biome
        run: pnpm biome ci .

      - name: Biome報告をPRコメントに投稿
        if: failure() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '⚠️ Biomeチェックが失敗しました。`pnpm check` を実行してください。'
            })

pre-commitフック(Husky + lint-staged)

# Huskyとlint-stagedインストール
pnpm add -D husky lint-staged

# Husky初期化
npx husky init
// package.json
{
  "scripts": {
    "prepare": "husky install"
  },
  "lint-staged": {
    "*.{js,ts,jsx,tsx,json}": [
      "biome check --write --no-errors-on-unmatched"
    ]
  }
}
# .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx lint-staged

GitLab CI

# .gitlab-ci.yml
biome:
  image: node:20
  stage: test
  script:
    - npm ci
    - npx @biomejs/biome ci .
  only:
    - merge_requests
    - main

パフォーマンス比較

ベンチマーク(中規模プロジェクト: 1000ファイル)

# ESLint + Prettier
time npm run lint:old
# 実行時間: 18.2秒

# Biome
time npm run check
# 実行時間: 0.3秒

# 約60倍高速!

大規模モノレポでの比較

# プロジェクト規模: 5000ファイル、200万行

# 従来ツール
ESLint:   2分30秒
Prettier: 45秒
合計:     3分15秒

# Biome
フォーマット + リント: 1.8秒

# 約100倍高速!

メモリ使用量比較

ESLint + Prettier: 800MB
Biome:             120MB

# メモリ使用量 85% 削減

高度な設定パターン

モノレポ設定

// apps/web/biome.json
{
  "extends": ["../../biome.json"],  // ルート設定を継承
  "formatter": {
    "lineWidth": 120  // このパッケージのみ行長を変更
  },
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": "error"  // Reactアプリなので厳格に
      }
    }
  }
}
// packages/shared/biome.json
{
  "extends": ["../../biome.json"],
  "linter": {
    "rules": {
      "suspicious": {
        "noConsoleLog": "error"  // ライブラリなのでconsole.log禁止
      }
    }
  }
}

プラグイン風のカスタムルール(外部ツール連携)

# Biomeはプラグインシステムがないため、
# カスタムルールは外部ツールと組み合わせる

# 例: type-coverageでTypeScriptの型カバレッジチェック
pnpm add -D type-coverage

# package.json
{
  "scripts": {
    "check": "biome check --write . && type-coverage --at-least 95"
  }
}

トラブルシューティング

よくある問題と解決策

# 問題1: Biomeが認識されない
# 解決: パスを明示的に指定
npx @biomejs/biome check .

# 問題2: VSCodeで動作しない
# 解決: Biome拡張機能を再インストール
# 1. 拡張機能をアンインストール
# 2. VSCode再起動
# 3. 拡張機能を再インストール

# 問題3: 既存コードとの互換性
# 解決: ignoreパターンを追加
{
  "files": {
    "ignore": ["legacy/**", "vendor/**"]
  }
}

# 問題4: パフォーマンスが遅い
# 解決: ignoreパターンを最適化
{
  "files": {
    "ignore": [
      "node_modules",
      "dist",
      "build",
      ".next",
      "coverage",
      "**/*.min.js",
      "**/*.bundle.js"
    ]
  }
}

まとめ

Biomeは以下のプロジェクトで特に有効です:

最適なユースケース:

  • TypeScript/JavaScriptプロジェクト全般
  • モノレポ(Turborepo、Nx等)
  • CI/CDパイプラインの高速化が必要
  • チーム開発での統一ツールチェーン
  • 大規模プロジェクト(1000+ ファイル)

移行のメリット:

  • 超高速: 従来比60〜100倍高速
  • シンプル: 設定ファイル1つに集約
  • 軽量: node_modules削減(200MB→10MB)
  • DX向上: VSCode統合、エラーメッセージが明確

移行時の注意点:

  • 一部ESLintプラグイン(eslint-plugin-react-hooks等)は代替手段が必要
  • カスタムルールはまだサポートされていない
  • エコシステムはまだ成長中(今後のアップデートに期待)

Biome v1.0のリリースにより、本番環境での使用が推奨されるレベルに到達しました。特にパフォーマンスと開発体験の向上は劇的で、新規プロジェクトでは第一選択肢となるでしょう。