Biome 2.0登場 - ESLint/Prettierを置き換える超高速ツールチェーン

2025.06.25

Biomeは、Rust製の超高速なJavaScript/TypeScriptツールチェーンです。ESLintとPrettierの機能を1つのツールに統合し、圧倒的な速度で開発体験を向上させます。2025年、Biome 2.0のリリースにより、さらに多くのプロジェクトでの採用が進んでいます。

Biomeとは

ツールチェーンの比較

flowchart TB
    subgraph Traditional["従来の構成"]
        Workflow1["開発ワークフロー"]
        ESLint["ESLint<br/>(JavaScript)"]
        Prettier["Prettier<br/>(JavaScript)"]
        TSC["TypeScript<br/>tsc"]
        Config1["設定ファイルが複数必要<br/>(.eslintrc, .prettierrc, tsconfig.json)"]

        Workflow1 --> ESLint
        Workflow1 --> Prettier
        Workflow1 --> TSC
        ESLint --> Config1
        Prettier --> Config1
        TSC --> Config1
    end
flowchart TB
    subgraph BiomeArch["Biomeの構成"]
        Workflow2["開発ワークフロー"]
        Biome["Biome (Rust)<br/>✓ Linter<br/>✓ Formatter<br/>✓ Import Sort"]
        Config2["biome.json 1ファイルで管理"]

        Workflow2 --> Biome --> Config2
    end

パフォーマンス比較

ツール1000ファイル処理メモリ使用量
ESLint + Prettier約30秒~500MB
Biome約0.5秒~50MB

約60倍高速、メモリ1/10

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

基本インストール

# npm
npm install --save-dev --save-exact @biomejs/biome

# pnpm
pnpm add --save-dev --save-exact @biomejs/biome

# yarn
yarn add --dev --exact @biomejs/biome

# bun
bun add --dev --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": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "always"
    }
  }
}

package.jsonのスクリプト設定

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

詳細な設定

完全な設定例

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "files": {
    "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.jsx"],
    "ignore": [
      "node_modules",
      "dist",
      "build",
      ".next",
      "coverage",
      "*.min.js"
    ]
  },
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "complexity": {
        "noExcessiveCognitiveComplexity": {
          "level": "warn",
          "options": {
            "maxAllowedComplexity": 15
          }
        },
        "noForEach": "warn"
      },
      "correctness": {
        "noUnusedVariables": "error",
        "noUnusedImports": "error",
        "useExhaustiveDependencies": "warn"
      },
      "performance": {
        "noAccumulatingSpread": "warn",
        "noDelete": "warn"
      },
      "security": {
        "noDangerouslySetInnerHtml": "error"
      },
      "style": {
        "noNonNullAssertion": "warn",
        "useConst": "error",
        "useTemplate": "error",
        "noParameterAssign": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "warn",
        "noDebugger": "error"
      },
      "nursery": {
        "useSortedClasses": {
          "level": "warn",
          "options": {
            "attributes": ["className", "class"],
            "functions": ["clsx", "cn", "cva"]
          }
        }
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 100,
    "attributePosition": "auto"
  },
  "javascript": {
    "formatter": {
      "enabled": true,
      "quoteStyle": "single",
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false
    },
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    }
  },
  "json": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100
    }
  },
  "css": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100,
      "quoteStyle": "double"
    },
    "linter": {
      "enabled": true
    }
  },
  "overrides": [
    {
      "include": ["*.test.ts", "*.test.tsx", "*.spec.ts"],
      "linter": {
        "rules": {
          "suspicious": {
            "noExplicitAny": "off"
          }
        }
      }
    },
    {
      "include": ["*.config.js", "*.config.ts"],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          }
        }
      }
    }
  ]
}

Linterルールのカテゴリ

ルールカテゴリ一覧

カテゴリルール例説明
a11y (アクセシビリティ)useAltText画像にalt属性を要求
useKeyWithClickEventsクリックイベントにキー操作
complexity (複雑性)noBannedTypes禁止された型の使用を検出
noForEachforEach → for…of を推奨
noExcessiveCognitiveComplexity認知的複雑度制限
correctness (正確性)noUnusedVariables未使用変数の検出
noUnusedImports未使用インポートの検出
useExhaustiveDependenciesuseEffect依存配列
performance (パフォーマンス)noAccumulatingSpreadスプレッド演算子の累積禁止
noDeletedelete演算子の使用を警告
security (セキュリティ)noDangerouslySetInnerHtmlXSS脆弱性の検出
noGlobalEvaleval()の使用禁止
style (スタイル)useConst再代入されない変数はconstを使用
useTemplate文字列連結よりテンプレートリテラル
noParameterAssignパラメータへの再代入禁止
suspicious (疑わしいコード)noExplicitAnyany型の使用を警告
noConsoleLogconsole.logの使用を警告
noDebuggerdebugger文の禁止

ルールの詳細設定例

{
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": {
          "level": "warn",
          "options": {
            "hooks": [
              {
                "name": "useQuery",
                "stableResult": [1]
              },
              {
                "name": "useMutation",
                "stableResult": [1]
              },
              {
                "name": "useCustomHook",
                "closureIndex": 0,
                "dependenciesIndex": 1
              }
            ]
          }
        }
      }
    }
  }
}

ESLint/Prettierからの移行

移行チェックリスト

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

# 2. 設定ファイルの初期化
npx @biomejs/biome init

# 3. ESLint設定からの移行(自動)
npx @biomejs/biome migrate eslint --write

# 4. Prettier設定からの移行(自動)
npx @biomejs/biome migrate prettier --write

ESLintルールの対応表

ESLintBiomeカテゴリ
no-unused-varsnoUnusedVariablescorrectness
no-consolenoConsoleLogsuspicious
eqeqeqnoDoubleEqualssuspicious
prefer-constuseConststyle
no-varnoVarstyle
@typescript-eslint/no-explicit-anynoExplicitAnysuspicious
react-hooks/exhaustive-depsuseExhaustiveDependenciescorrectness
jsx-a11y/alt-textuseAltTexta11y

段階的な移行戦略

// biome.json - 段階的移行用設定
{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      // 最初は警告のみ
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "off"  // 最初は無効化
      }
    }
  }
}
# 移行後にESLint/Prettierを削除
npm uninstall eslint prettier eslint-config-prettier eslint-plugin-*

# 設定ファイルの削除
rm .eslintrc* .prettierrc* .eslintignore .prettierignore

エディタ統合

VS Code

// .vscode/extensions.json
{
  "recommendations": ["biomejs.biome"]
}
// .vscode/settings.json
{
  // Biomeをデフォルトフォーマッターに
  "editor.defaultFormatter": "biomejs.biome",
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

  // 保存時に自動フォーマット
  "editor.formatOnSave": true,

  // 保存時にコードアクション実行
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },

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

Neovim (nvim-lspconfig)

-- init.lua
require('lspconfig').biome.setup({
  cmd = { 'npx', 'biome', 'lsp-proxy' },
  root_dir = require('lspconfig.util').root_pattern('biome.json', 'biome.jsonc'),
  single_file_support = false,
})

-- null-ls.nvimとの統合
local null_ls = require('null-ls')
null_ls.setup({
  sources = {
    null_ls.builtins.formatting.biome,
    null_ls.builtins.diagnostics.biome,
  },
})

JetBrains IDE (WebStorm等)

設定手順:
1. Settings → Languages & Frameworks → JavaScript → Code Quality Tools → Biome
2. "Enable" にチェック
3. Biome package: node_modules/@biomejs/biome
4. Configuration file: biome.json

フォーマット設定:
1. Settings → Editor → Code Style
2. "Enable EditorConfig support" をオフ
3. Settings → Tools → Actions on Save
4. "Reformat code" と "Run Biome" にチェック

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

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Biome CI
        run: npx @biomejs/biome ci .

  # PRにインライン注釈を追加
  lint-review:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - name: Setup Biome
        uses: biomejs/setup-biome@v2
        with:
          version: latest

      - name: Run Biome with reviewdog
        uses: reviewdog/action-biome@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          reporter: github-pr-review

GitLab CI

# .gitlab-ci.yml
stages:
  - lint

biome:
  stage: lint
  image: node:20-alpine
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npx @biomejs/biome ci .
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

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

# Huskyのインストール
npm install --save-dev husky lint-staged
npx husky init
// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx,json,css}": [
      "biome check --write --no-errors-on-unmatched"
    ]
  }
}
# .husky/pre-commit
npx lint-staged

高度な使用方法

プラグインAPI(実験的機能)

// biome-plugin.js - カスタムルールの例
export default {
  name: 'my-custom-rules',
  rules: {
    noTodoComments: {
      meta: {
        docs: {
          description: 'Disallow TODO comments in production code',
        },
      },
      create(context) {
        return {
          Comment(node) {
            if (node.value.includes('TODO')) {
              context.report({
                node,
                message: 'TODO comments should be resolved before merge',
              });
            }
          },
        };
      },
    },
  },
};

Monorepo設定

// ルートのbiome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": [],
  "files": {
    "ignore": ["packages/*/dist", "packages/*/node_modules"]
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true
  }
}
// packages/web/biome.json - パッケージ固有の設定
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": ["../../biome.json"],
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": "warn"
      }
    }
  }
}

カスタムインポートソート

{
  "javascript": {
    "organizeImports": {
      "groups": [
        ["react", "react-dom"],
        ["^@?\\w"],
        ["^@/"],
        ["^\\.\\."],
        ["^\\."]
      ]
    }
  }
}

トラブルシューティング

よくある問題と解決策

# キャッシュのクリア
rm -rf node_modules/.cache/biome

# 詳細なエラー出力
npx @biomejs/biome check --verbose .

# 特定のファイルのデバッグ
npx @biomejs/biome lint --verbose src/problematic-file.ts

# 設定の検証
npx @biomejs/biome check --config-path biome.json --verbose

エラー抑制コメント

// ファイル全体で特定のルールを無効化
// biome-ignore-all lint/suspicious/noExplicitAny: Legacy code

// 次の行のみ無効化
// biome-ignore lint/suspicious/noExplicitAny: Necessary for this API
const data: any = response.data;

// 複数ルールの無効化
// biome-ignore lint/style/useConst lint/correctness/noUnusedVariables: Intentional
let unusedVar = 'test';

// フォーマットの無効化
// biome-ignore format: Keep this formatting
const matrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

パフォーマンスベンチマーク

大規模プロジェクトでの比較(10,000ファイル):

ツールlint時間format時間メモリ使用量
ESLint120秒-1.2GB
Prettier-45秒800MB
ESLint+Prettier165秒(合計)2.0GB
Biome2秒1.5秒150MB
改善率60x高速30x高速13x削減

まとめ

Biomeは、フロントエンド開発のツールチェーンを大きく改善します。

Biome導入のメリット

項目ESLint+PrettierBiome
速度遅い超高速(60倍以上)
設定ファイル複数1ファイル
依存関係多数1つ
メモリ使用量
設定の一貫性衝突の可能性統合済み

導入推奨ケース

  • 新規プロジェクト
  • CIの高速化が必要なプロジェクト
  • 設定の簡素化を求めるチーム
  • Monorepo環境

Biomeは、JavaScriptエコシステムの新しいスタンダードとなりつつあります。

参考リンク

← 一覧に戻る