😂

モノレポのプロジェクトでhuskyを設定してみた

2024/05/16に公開
1

フロントエンドの静的テストとして、huskyとlint-stagedを用いてeslintとprettierを実行しようとしたところ、.gitpackage.jsonのディレクトリが同一でないことで詰まったので備忘録。

ちなみに、ディレクトリの構造はこんな感じで、husky@9.0.11lint-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ディレクトリあるけどなんでなん?と調べ回ったところ、
どうやら.gitpackage.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-commitcommit-msgを設定していく。

lint-stagedとpre-commitを設定する

npx husky initpre-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も設定したけど、書くの疲れたからこの辺で終了。
参考記事だけ置いておきます。先人の皆様、超感謝してます。

https://qiita.com/les-r-pan/items/c03f12bc1693983daa70
https://zenn.dev/g_okawara/articles/850d8e6729edfb

おわり。