🌧️

【Next.js】eslint + pretteirをやめてBiomeにした話

2024/01/16に公開

はじめに

Next.jsなどReactのプロジェクトにはlinterformatterが必須でeslintpretteirを使うと思います。

しかし、導入するとなると考慮すべき点や面倒な点が結構あります。
以下は一例です。

  • eslintprettierは設定が複数あり、プラグインのインストールが必要
  • eslint-plugin-prettierを使えば、pretteirがなくてもformatterは実現できるため、そもそもprettierいるのか問題
  • 逆にeslintlinterとしての役割のみにして、formatterの機能は持たせたくない

そこででてくるのがBiomeです。

Biomeとは

一言でいうとeslintprettierを一つにしたものです。
以下、公式の引用とページです。

Biome はWebプロジェクトのための高性能なツールチェーンであり、プロジェクトの健全性を維持するための開発者ツールの提供を目的としています。

Biome は JavaScript, TypeScript, JSX そして JSON 向けの高速なFormatterであり、Prettier との互換性は97% を達成しています。

Biome は JavaScript, TypeScript, JSX のための高性能なLinter であり、ESLint, TypeScript ESLint, その他のソースから 170以上のルールを提供しています。Biome は詳細で文脈に沿った結果を出力するため、コードを改善し、より良いプログラマになるための手助けをします!

Biome は最初からエディタ内で対話的に使用できるように設計されています。 あなたがコードを書いているときに、形の崩れたコードを format と lint することができます。

https://biomejs.dev/ja/

これはありがたいということで、早速、Next.jsのプロジェクトに導入してみました。

Biomeをプロジェクトに導入

それではBiomeをプロジェクトに導入していき、設定まで行っていきましょう。

Biomeをインストール

まず、公式ドキュメントに沿って、プロジェクトのディレクトリにBiomeをインストールします。

https://biomejs.dev/ja/guides/getting-started/

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

次に、Biomeの設定ファイルであるbiome.jsonを作成します。
以下のコマンドで作成します。

fish
npx @biomejs/biome init

ファイルの内容はデフォルトで以下のようになっていると思います。

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

デフォルトでは、linterの推奨ルールとformatterが有効になっている状態です。
formatter.enabled: falseと明示的にformatterを無効にしない限りはformatterは有効化されているようです)

package.jsonの編集

BiomelinterformatterをCLIからも使用できるようにします。
以下のようにpackage.jsonscriptsにコマンドを追加してください。
<files>には任意のファイルやディレクトリを指定してください(例えば./srcなど)

package.json
"lint": "biome lint -- apply <files>",
"format": "biome format <files> --write",
"check": "biome check --apply <files>"

各コマンドは以下のような動きをします。

  • format: --writeオプションを指定することで、ファイルやディレクトリをフォーマットする
  • lint: --applyオプションを指定することで、ファイルやディレクトリに対してLintを実行し、修正できる部分は修正する(eslintのfixと同じ)
  • check: formatlintimportの整理を実行(全てを実行する)

エディタの設定

Biomeを使用する以前はエディタのdefaultFormatterにはprettierを使用していたので、それをBiomeに変更する必要があります。

まずは、VSCodeの拡張機能をインストールします。
https://marketplace.visualstudio.com/items?itemName=biomejs.biome

次に、公式ドキュメントに沿って、settings.jsonを編集します。
(VSCodeの「設定」(Macの場合、「command + ,」) > 上部にある「設定(JSON)を開く」から開く)

https://biomejs.dev/ja/reference/vscode/

settings.jsonを開いたら、以下の設定を追加します。
(元々、prettierを使用していた場合は、"editor.defaultFormatter"biomejs.biomeに書き換える必要があります。もちろん、言語ごとに設定も可能です。)

settings.json
"editor.codeActionsOnSave": {
  "quickfix.biome": true,
  "source.organizeImports.biome": true
},
"editor.defaultFormatter": "biomejs.biome",
"[javascript]": {
   "editor.defaultFormatter": "biomejs.biome"
},

"editor.codeActionsOnSave""quickfix.biome"で保存時にコードの修正がなされるようになり、"source.organizeImports.biome"でインポートの並び替えが行われます。

Biomeの設定を編集

私の場合は、以下のような設定を使用することにしています。

考え方としては、まずfilesignoreformatterlinterを適用させたくないものを指定します。

formatterは個人的な好みやチームによりけりなので、基本はデフォルトの設定を適用し、追加の設定や変更したい設定を記述するようにしています。

linterrecommendedでも良いとは思いますが、私は基本的に全て適用させたい派なので、そのようにし、外したい設定のみoffにするようにしています。

overrideでは「このファイルだけ、この設定を付けたい・offにしたい」というものを記述しています。
今回の場合、プロジェクトがNext.jsapp routerなので、export defaultしないといけないファイルがあるなどします。

そのため、該当するファイルにのみnoDefaultExportoffにするようにしています。

biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.5.2/schema.json",
  "files": {
    "ignore": ["public"]
  },
  "organizeImports": {
    "enabled": true
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded"
    }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "all": true,
      "nursery": {
        "noNodejsModules": "off"
      }
    }
  },
  "overrides": [
    {
      "include": [
        "next.config.js",
        "layout.tsx",
        "page.tsx",
        "loading.tsx",
        "error.tsx",
        "not-found.tsx"
      ],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          }
        }
      }
    }
  ]
}

それでは、Biomeの具体的な内部仕様について、概要を解説します。

Analyzer

まず、Analyserですが、これは"organizationImports"の部分になります。
https://biomejs.dev/ja/analyzer/

これはimportのソートを行う・行わないの設定ができます。
import文をソートする場合、Biomeでは距離によってソートされます。
具体的には、ユーザー(ファイル)から遠いモジュールほど上に配置されるようです。

例えば以下のimport文の場合は、

import './globals.css'
import { Inter } from 'next/font/google'
import type { ReactNode } from 'react'
import type { Metadata } from 'next'

次のようにソートされます。

import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import type { ReactNode } from 'react'
import './globals.css'

グループソートは以下のようにすることで実現できます。

// group1
import './globals.css'

// group2
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import type { ReactNode } from 'react'

このように改行を入れるとグループに分けてソートできるので、非常に使いやすいです。

Formatter

次にFormatterですが、これは"formatter"の部分でprettierの機能に該当します。
https://biomejs.dev/ja/formatter/

ただ、Biomeでは"formatter": {}と記述することなく、デフォルトで以下の設定が適用されています。

{
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "tab",
    "indentWidth": 2,
    "lineWidth": 80,
    "lineEnding": "lf",
    "ignore": []
  }
}

そのため、基本的にデフォルトのままで上書きしたいものを記述する方式で良いと思います。
もちろん、明示的に記述したい方は記述しても良いとは思います。(このあたりは好みの問題です)

言語ごとの設定も追加でき、例えば、JavaScriptでは以下がデフォルトの設定となっています。

{
  "javascript": {
    "formatter": {
      "arrowParentheses":"always",
      "jsxQuoteStyle": "double",
      "semicolons": "always",
      "trailingComma": "all",
      "quoteProperties": "asNeeded",
      "bracketSpacing": true,
      "bracketSameLine": false
    }
  }
}

私の設定ではデフォルトを上書きし、以下の記述をしています。

"javascript": {
  "formatter": {
    "quoteStyle": "single",
    "semicolons": "asNeeded"
  }
}

このようにすることでJavaScriptではシングルクォートと文末のセミコロンをなしにするformatができます。

formatを無視したい場合、以下のコメントを該当行に記載します。

// biome-ignore format: <説明文>

Linter

続いてLinterですが、これは"linter"の部分でeslintの機能に該当します。
https://biomejs.dev/ja/linter/

デフォルトではBiomeが推奨するルールが適用されます。

ルールを有効化するには、以下のように"rules"にグループとルール名を指定し、"error""warn"を指定します。

逆に、無効化したい場合は、ルール名に対して"off"を指定することで無効化することができます。
このように適用させたい(させたくない)ルールをカスタマイズすることができます。

{
  "linter": {
    "enabled": true,
    "rules": {
      "style": {
        "useBlockStatements": "error",
        "useShorthandArrayType": "warn",
        "noShoutyConstants": "off"
      }
    }
  }
}

linterを無視したい場合、以下のコメントを該当行に記載します。

// biome-ignore lint: <explanation>
// biome-ignore lint/suspicious/noDebugger: <explanation>

linterの場合は、それぞれ以下の意味があります。

  • biome-ignore: 抑制コメントの開始を表す
  • lint: linterを抑制することを表す
  • /suspicious/noDebugger: このコメントは任意で、抑制したいルールのグループと名前を表す
  • <explantation>: ルールが無効になっている理由を表す

overrides

最後にoverridesでは、特定のファイルに対するBiomeの動作を設定することができます。
https://biomejs.dev/ja/reference/configuration/#overrides

例えば、私の設定のincludeではincludeに指定したパターンにマッチするファイルにのみoverridesで指定した設定を適用することができます。
この場合は、指定したファイルに対して、linternoDefaultExportルールを無効にするような設定をしています。

"overrides": [
  {
    "include": [
      "next.config.js",
      "layout.tsx",
      "page.tsx",
      "loading.tsx",
      "error.tsx",
      "not-found.tsx"
    ],
    "linter": {
      "rules": {
        "style": {
          "noDefaultExport": "off"
        }
      }
    }
  }
]

他にも色々と設定があるので、詳しくはドキュメントを見てみてください。
ドキュメントは、日本語化されていない部分もありますが、大体は日本語化されているので読みやすいと思います。

おわりに

個人的には、今後はBiomeを使っていきたいですし、既存のプロジェクトもBiomeにしたいと思うくらい良かったです。
ぜひ使ってみてください。

参考文献

https://biomejs.dev/ja/
https://biomejs.dev/ja/guides/getting-started/
https://github.com/biomejs/biome?tab=readme-ov-file
https://marketplace.visualstudio.com/items?itemName=biomejs.biome
https://biomejs.dev/ja/reference/vscode/
https://biomejs.dev/ja/analyzer/
https://biomejs.dev/ja/formatter/
https://biomejs.dev/ja/linter/
https://biomejs.dev/ja/reference/configuration/#overrides

Discussion