💨

Monorepo で husky + biome を設定した備忘録

に公開

Monorepo 環境で huskyBiome を動かしてみたのでその備忘録です。

やってみてから気づきましたが、Monorepo 環境でやるなら Lefthook を使った方が楽そうです。

一応 husky でもできるということでこの記事は続けます。

ちなみに、Git Hooks を利用して Biome で動かしたい場合のガイドは https://biomejs.dev/recipes/git-hooks/#_top にありました。

もし本記事の内容について誤りがあればご指摘いただけますとありがたいです 🙇

設定の流れ

Biome の設定後、husky を利用して commit 時に Biome が動くようにします。

モノレポの構成について

以下のように、packages 配下にモノレポ構成で管理したいパッケージを置いています。
パッケージマネージャは pnpm です。

ルートディレクトリ名は monorepo-husky-and-biome としています。

monorepo-husky-and-biome
├── package.json
├── packages
│   ├── packages-a
│   ├── packages-b
│   └── packages-c
└── pnpm-workspace.yaml

packages 配下のパッケージをサブパッケージと呼んでいくことにします(正しい呼称かわかってないです 🙇)。

Biome の設定

Biome v2 でモノレポでの使い勝手がよくなったらしく、Biome の設定をルート直下においてそれをサブパッケージで継承できるようになっています。

https://tech.furyu.jp/entry/2025/06/20/100053

Biome のインストール

Biome のインストールは公式のガイド通りに行います。

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

ルート直下で Biome をインストールするためのコマンドを実行します。

pnpm add -D -E @biomejs/biome

執筆時点で Biome v2.1.1 がインストールされています。

Biome の設定を初期化するコマンドを実行します。

pnpm exec biome init

ルート直下に biome.json が生成されているはずです。

モノレポ用に Biome を設定

Biome 公式のモノレポ利用時のガイドを参照しつつ行います。

https://biomejs.dev/guides/big-projects/#monorepo

まず、各サブパッケージに biome.json を下記の内容で配置していきます。

packages/packages-a/biome.json
{
    "root": false,
    "extends": "//"
}

大事なのは "extends": "//" という部分です。extends プロパティでは指定した設定ファイルを継承してくれるため、今回 // とすることでルート直下の ./biome.json を継承するように指定しています。

ここまでで モノレポで Biome を動かすための設定は完了です。

Biome の動作確認

問題ないか動作確認をします。
ここは飛ばしても大丈夫です。

packages/packages-a/index.ts を作成し、Biome が Lint してくれる以下のコードを書きます。

packages/packages-a/index.ts
let num = 10;

console.log(num);

Recommended rules に含まれている const を使おうというルールの指摘が当たるコードになっています。

https://biomejs.dev/linter/rules/use-const/

packages/packages-a/ に移動し、index.ts をチェックさせます。

packages/packages-a/
pnpm exec biome check index.ts

設定がうまくいっていれば以下のように Lint された内容が出力されるはずです。

index.ts:1:1 lint/style/useConst  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ⚠ This let declares a variable that is only assigned once.
  
  > 1let num = 10;
      │ ^^^
    23 │ console.log(num);'num' is never reassigned.
  
  > 1let num = 10;
      │     ^^^
    23 │ console.log(num);
  
  ℹ Safe fix: Use const instead.
  
    1   │ - let·num·=·10;
      1 │ + const·num·=·10;
    2 23 3 │   console.log(num);
  

Checked 1 file in 1431µs. No fixes applied.
Found 1 warning.

確認が済んだので husky の設定に移ります。

husky の設定

husky を利用して biome を動かすための設定をしていきます。
なお、husky 単体だけでは具体的な動作を起こせないので lint-staged と組み合わせて使います。

husky はセキュリティ上の都合で、モノレポのような環境で親ディレクトリに遡ってのインストールができないらしいです。

そのため husky を初期設定する場合、.git があるパッケージのルートディレクトリでコマンドを実行しないといけません。
なので、一般的な husky の設定のように package.json"prepare": "husky" とするだけでは動いてくれません。

そこでどうするかというと .git のあるディレクトリに移動してから husky コマンドのオプションにサブパッケージのパスを指定するとできます。

これは公式ドキュメントにも記載がありました。

https://typicode.github.io/husky/how-to.html#project-not-in-git-root-directory

モノレポ用の設定をするにあたり以下の記事を参考にさせていただきました。

モノレポ用に husky & lint-staged を設定

まず huskylintstaged をインストールします。

パッケージのルートディレクトリでインストール用のコマンドを実行します。

monorepo-husky-and-biome/
pnpm add -D husky lint-staged

続いて以下のように、packages/packages-a/package.jsonscripts プロパティの "prepare" のところにコマンドを追加します。

packages/packages-a/package.json
     "scripts": {
         "test": "echo \"Error: no test specified\" && exit 1",
+        "prepare": "cd ../.. && husky packages/packages-a/.husky"
     },

pnpm run prepare を実行して husky をインストールします。

インストールできれば、 packages/packages-a/ 配下に .husky というフォルダができているはずです。

続いて lint-staged を設定して commit 時に Biome が動くようにします。

package.jsonlint-staged 関連の記述を入れます。

packages/packages-a/package.json
+    "lint-staged" : {
+        "*.ts": "biome check --write"
+    },

*.ts で拡張子が ts のファイルを対象に、右側に書いてある biome check --write コマンドを実行してくれます。

次に .husky の中に pre-commit というファイルがあるので、それを編集します。
もしなかったら作成してください。

packages/packages-a/.husky/pre-commit
cd packages/packages-a
pnpm run lint-staged

モノレポでは、.git があるパッケージのルートディレクトリでコマンドが実行されます。
なので、今回の対象ディレクトリである packages/packages-a まで移動させるために 1 行目の記述をしています。
2 行目では先ほど設定した lint-staged を動かしています。

ここまでで husky + lint-staged を利用して Biome を動かせるようになったので、index.ts を commit してみます。

packages/packages-a
git add index.ts
git commit -m "biome が動くかどうかテスト"

commit 差分に .ts ファイルが含まれていて husky が動いた場合は以下のように四個ぐらいのチェックマークが出てくれます。

✔ Backed up original state in git stash (063ed90)
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...

設定が上手くいっていない場合には → No staged files found. と、対象ファイルがないと言われる場合があります。

packages-b で  *.ts を commit した場合の挙動

packages-a での設定が出来たので、それが他のサブパッケージに影響を及ぼさないか確認してみます。

husky の設定をしていない packages/packages-bindex.ts を追加して commit してみると → No staged files found. となりました。
husky が動くのは意外でしたが packages/packages-a の設定が伝播していないので問題ない挙動です。

git コマンドを叩く場所で挙動が変わりそうですが、ルートディレクトリでも packages/packages-b でも同様の表記なので husky 自体はどこでも動くのかもしれない。
理解が浅いですがここは深追いしません……。

ルートディレクトリから packages/packages-a の commit を打つとちゃんと設定した通りに Biome が動いてくれるので多分挙動的に問題はないのかも。

私は Lefthook に乗り換え予定なので実際の使用感を試してみてここら辺の認識を深めるのは多分しなそうです。気になる方はお手数ですがご自身で検証していただけるとありがたいです 🙇

終わりに

Monorepo 環境で husky + lint-staged + Biome を利用して commit 時に Lint してくれる設定については以上のとおりです。

備忘録なので至らぬところが多数と思います。間違いなどあれば宜しければご指摘いただけるとありがたいです。

参照させていただいた記事

https://zenn.dev/risu729/articles/latest-husky-lint-staged

https://zenn.dev/g_okawara/articles/850d8e6729edfb

https://qiita.com/les-r-pan/items/c03f12bc1693983daa70

https://zenn.dev/ryoooosk/articles/8901e8a3f25a38

Discussion