モノレポのプロジェクトでhuskyを設定してみた
フロントエンドの静的テストとして、huskyとlint-stagedを用いてeslintとprettierを実行しようとしたところ、.gitとpackage.jsonのディレクトリが同一でないことで詰まったので備忘録。
ちなみに、ディレクトリの構造はこんな感じで、husky@9.0.11、lint-staged@15.2.2でのお話。
root/
|--.git <--
|--client
| |--src
| └--package.json <--
|--server
インストール
とにもかくにも、まずはインストール。
まずはhuskyのドキュメント通りやってみる。
npm i -D husky lint-staged
ついでに、lint-stagedもインストールしておく。
lint-stagedは、コミットしたいファイルにだけeslintとprettierをかけるのに必要。
huskyをインストールしたら初期化を行う。ドキュメント通りのコマンドを実行する。
npx husky init
はい。さっそく怒られる。
.git can't be found
huskyはプロジェクトのrootで使われる想定ぽい
.gitディレクトリあるけどなんでなん?と調べ回ったところ、
どうやら.gitとpackage.jsonが同一ディレクトリにないといけないぽい。
(けっこう前だったけど、同じ内容のissueが出ていたのを見たらプロジェクトのrootで使ってって書いてあった)
つまり、遠く離れた.gitを気を利かせて探しに行ってくれるわけではないらしい。
それなら探し方を教えてあげよう。
husky initの実行でpackage.jsonのscriptsに追加されたprepareを変更する。
"scripts": {
...,
...,
"prepare": "cd .. && husky client/.husky"
}
今回の筆者のケースだと、package.jsonから見て.gitは親ディレクトリにいる。
だから、まずcd ..をして親ディレクトリに行く。そんでhuskyを実行するのだけど、初期化を行う場所(client/.husky)も渡してあげる。
本来というか公式ドキュメントだと、npx husky initでセットアップ終了でprepareコマンドは叩く必要がない。今回は.gitが同一ディレクトリ内にいないから、prepareコマンドでセットアップ(準備)してもらう。
npm run prepare
ついに、サブディレクトリ内に.husky/_ が爆誕する。
この中にはhuskyの実行環境が置かれているぽいが、gitignoreされているし細かいことは置いておく。
ここまでで、huskyのセットアップは終了。
pre-commitとcommit-msgを設定していく。
lint-stagedとpre-commitを設定する
npx husky initでpre-commitファイルができてるから、実行したいスクリプトを書けばいいだけ。
なんだけども、lint-stagedを使わないとcommit対象外のファイルにも実行されてしまうので、package.jsonに実行したい処理を含めたlinst-stagedを追加する。
"lint-staged": {
"*.ts": ["prettier --write", "eslint"]
}
とりあえず、prettierとeslintを入れてみる。eslintでフォーマットまでかけたい場合はeslint --fixの方が良い。今回はちょっと怖いのでやめておく。
lint-stagedの設定ができたのでここで一度npm iしておく。
そんで、pre-commitファイルにlint-stagedを実行するスクリプトを書く。
cd client
npx lint-staged
このファイル自体はサブディレクトリ内(今回で言うと/client)にあるが、呼び出し元はルートディレクトリの.git/hooksになる。(そもそもhuskyはgitのhooksの実行内容をhuskyに向けるためのツールらしい)
だから、まずpackage.jsonがあるディレクトリまで移動してもらう。
移動を拒むとnode_moduleがないから怒られる。
いざcommitの時!
いよいよcommitしてみる。
vscodeのgitの拡張機能のやつでcommitすると経過が出なくてちゃんとpre-commit実行されているか分かりにくいので、shellに叩き込む。
まずは、eslintでerrorが出ているファイルを準備してちゃんとcommitが弾かれるか確認する。
git commit -m "chore: fail commit"

お見事!無事にeslintで弾かれた!
次にerrorがないファイルはちゃんとcommitが通るか確認する。
git commit -m "chore: success commit"

無事にcommitされた😂
これでテストトロフィーの最下層、静的テストが自動で行える!
commit-msgも設定したけど、書くの疲れたからこの辺で終了。
参考記事だけ置いておきます。先人の皆様、超感謝してます。
おわり。
Discussion
分かりやすい記事あった