🔧

Next.js 16でBiomeに移行して分かったこと ─ 実際に動かした所感

に公開

本記事のサマリ

つい先日、Biomeについて学ぶ勉強会を一人でYouTube配信しながら、誰も来ない勉強会でただ喋りながら発信し続けるという、狂気に近い勉強会を主催しました...。(是非次は誰か遊びに来てくだされ!)

そこで学んだことを整理しておこうと思います。実際に動かしてみないと分からないことって、結構ありますからね。

今回のリポジトリは下記なので、是非ご参照ください。

https://github.com/toto-inu/lab-202511-biome

(YouTubeで迷走している私の動画↓)

https://youtube.com/live/SER4JZNdEvI

検証した内容

今回は以下の2つのNext.js 16プロジェクトを用意して比較検証しました:

  1. Biomeベース: 最初からBiomeを使ってcreate-next-appしたプロジェクト
  2. ESLint+Prettierベース: ESLintを使ってcreate-next-appし、Prettierを手動で追加したプロジェクト

プロジェクトの作成には以下のコマンドを使いました:

bunx create-next-app@latest

まずはBiomeベースのプロジェクトでbiome.jsonの設定内容を読み解き、その後でESLint+PrettierからBiomeへの移行を実際に試してみました。

biome.jsonの設定を読み解く

Lintルールのカテゴライズが分かりやすい

Biomeの公式ドキュメントを見ながらbiome.jsonを読んでいて、まず驚いたのがLintルールのカテゴライズです。ESLintの時は3種類程度のカテゴリしかなかった気がするのですが、Biomeでは以下の8つに整理されています:

  • a11y(アクセシビリティ)
  • complexity(複雑さ)
  • correctness(正しさ/誤り)
  • performance(性能)
  • security(セキュリティ)
  • style(コーディングスタイル)
  • suspicious(怪しいコード/バグになりやすい可能性)
  • nursery(実験的ルール/開発中)

公式ドキュメントでも「ESLintのインスパイア系」と言っている通り、ESLintのルールをそのまま移植したわけではなく、実装されていないものもあります。ただ、このカテゴライズは覚えられるぐらいの数で、かなり分かりやすくなったなという印象です。

推奨設定の分かりやすさ

https://www.biomejs.cn/ja/linter/#推奨ルール

Biomeのドキュメント上では、LintやFormatの推奨設定に分かりやすくチェックマークがついているんですね。もし自分の思った通りのルールじゃないなと感じたら、まずはドキュメントを確認して、それが推奨設定なのかどうかをチェックするところから始めると良さそうです。

特に、アクセシビリティ周りのlint設定の多くが推奨で、デフォルトで適用される点は素敵だなと感じました。

domains機能でまとまった設定を導入

https://biomejs.dev/ja/linter/domains/

domains機能も面白い機能でした。これによって、Next.js用やReact用、Vue.js用といったまとまったコーディング規約(lint設定)を簡単に導入できるんです。

最初からBiomeでcreate-next-appした場合の設定では、以下のようにdomainsが設定されていました:

"domains": {
  "next": "recommended",
  "react": "recommended"
}

ESLint+PrettierからBiomeへの移行を試す

移行手順

実際の移行手順は以下の通りです。コマンドをただ実行するだけではなく、事前準備が必要なのがポイントでした:

  1. Biomeパッケージをインストール
  2. biome initでbiome.jsonを作成
  3. 移行スクリプトを実行

具体的には、以下のコマンドを実行しました:

bunx biome migrate eslint --write
bunx biome migrate prettier --write

--writeオプションをつけることで、既存のbiome.jsonに設定を上書きする形で移行が行われます。

移行後のbiome.jsonの膨張問題

移行スクリプトを実行してみて驚いたのが、biome.jsonの中身が予想以上に膨れ上がったことです。移行後の設定ファイルがこちらです:

{
    "$schema": "https://biomejs.dev/schemas/2.3.2/schema.json",
    "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true },
    "files": { "ignoreUnknown": false },
    "formatter": {
        "enabled": true,
        "formatWithErrors": false,
        "indentStyle": "space",
        "indentWidth": 4,
        "lineEnding": "lf",
        "lineWidth": 80,
        "attributePosition": "auto",
        "bracketSameLine": false,
        "bracketSpacing": true,
        "expand": "auto",
        "useEditorconfig": true
    },
    "linter": {
        "enabled": true,
        "rules": {
            "recommended": false,
            "complexity": { "noUselessTypeConstraint": "error" },
            "correctness": { "noUnusedVariables": "error" },
            "style": {
                "noCommonJs": "error",
                "noNamespace": "error",
                "useArrayLiterals": "error",
                "useAsConstAssertion": "error"
            },
            "suspicious": {
                "noExplicitAny": "error",
                "noExtraNonNullAssertion": "error",
                "noMisleadingInstantiator": "error",
                "noNonNullAssertedOptionalChain": "error",
                "noUnsafeDeclarationMerging": "error",
                "useNamespaceKeyword": "error"
            }
        },
        "includes": [
            "**",
            "!.next/**",
            "!out/**",
            "!build/**",
            "!next-env.d.ts"
        ]
    },
    // ... 長い設定が続く
}

いや多すぎ...(是非実際のコードはgitで見てください)
正直、これを管理するのは大変そうだなというのが率直な感想です。

段階的移行の提案

もし私が本番環境で移行するとしたら、一括移行よりも領域を絞ってちょっとずつ拡大していく方が良さそうです。フォーマットを適用する範囲を、biome.jsonで管理している部分を少しずつ広げていく感じでしょうか。

ただ、そこまでしてやるかというところですね。後述しますが、新しいプロジェクトでBiomeを使う方が推奨設定でかなり少ない設定から始められるので、個人的にはそちらの方が良いかなと思いました。

overrides機能について

Biomeにはoverrides機能があり、特定のフォルダに対して独自のformatやlintルールを適用できます。これはESLintの頃にもあったかもしれませんが、改めて便利だと感じました。

例えば、GraphQLでGenerated Folderを、フロント側で使う型生成用として用意したとします。そこは自動生成されるファイルなので、フォーマットされるべきではありませんよね。自動生成ツールに任せるべきだと思うので、そういうところにはBiomeの設定を適用しない方が良さそうです。

新規プロジェクトでの導入がおすすめ

比較として、最初からBiomeでcreate-next-appした場合のbiome.jsonを見てみましょう:

{
  "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "ignoreUnknown": true,
    "includes": ["**", "!node_modules", "!.next", "!dist", "!build"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noUnknownAtRules": "off"
      }
    },
    "domains": {
      "next": "recommended",
      "react": "recommended"
    }
  },
  "assist": {
    "actions": {
      "source": {
        "organizeImports": "on"
      }
    }
  }
}

移行後の設定と比べると、圧倒的にシンプルですね。推奨設定を有効にして、domainsでNext.jsとReactの設定を入れるだけで、最低限必要な設定が整います。

まとめ

実際に手を動かしてBiomeを検証してみて、いくつかの発見がありました。

ESLintと比べてルールのカテゴライズが整理され、公式ドキュメントの推奨設定の表示も分かりやすくなっています。特にアクセシビリティ周りがデフォルトで適用される点は、モダンな開発では重要ですね。

一方で、既存のESLint+Prettierプロジェクトから移行する場合は、設定ファイルが膨れ上がる問題があります。段階的な移行を検討するか、思い切って新規プロジェクトでBiomeを採用する方が現実的かもしれません。

今後Biomeを導入するとしたら、個人的には最初からBiomeで始められるプロジェクトの方が良さそうだと感じました。推奨設定で少ない設定から始められて、必要に応じてカスタマイズしていけば良いでしょう。

ほぼ一人勉強会という少し寂しい形でしたが、実際に手を動かして得られた知見は貴重でした。皆さんもBiomeを検討される際の参考になれば幸いです。


参考リンク

株式会社StellarCreate | Tech blog📚

Discussion