notebook

都内でWEB系エンジニアやってます。

Husky + lint-stagedでCIの前にprettierを適用する

仕事で見ていいなと思ったので自分でもやってみる

方法は色々ありそうなのでとりあえずメモとして残しておく

CIでlintやprettierなどをチェックしてコーディングスタイルなどを保っていたが

CIでprettierチェックするとpushした結果prettier掛け忘れてた場合もう一度pushしなくてはならず面倒になる

push時に自動でprettier掛けてpushするなりcommitフックなりでpush前に自動でprettier掛けたいが、よくあるgitのhooksを使う方法は共有がしづらかったりなかなかやりづらいなーと思っていた

そこでHuskyの出番

Huskyを使えば簡単にgitのcommit hookのようにコマンドを差し込める

さらにlint-stagedでステージに上がっている変更に対してコマンド(今回はprettier)を実行できます

組み合わせるとHusky + lint-stagedでコミット時にprettierでフォーマットしてからcommitできる仕組みが作れます

開発時にprettierすらも意識しなくて良い感じに!

  • install
npm install --save-dev husky lint-staged

lint-staged

okonet/lint-staged: 🚫💩 — Run linters on git staged files

github.com

ステージングにある差分に対してあらかじめ設定したコマンドを実行させることができる

設定はYML JSON JSなど書きやすいフォーマットで書ける

フィルターだったりパスだったりとオプションをカスタマイズしていくことになると.jsで書く事になる

prettierのサンプルが公式にあるのでそれを参考にする

prettier --wirteeslint --fix など変更してそのまま反映させたい場合

git addコマンドも追加しておく

  • lint-staged.config.js
module.exports = {
  '**/*.ts': ["prettier --write --single-quote", "git add"]
}

試しにTypeScriptのファイルを使ってstageにあげる

git diff --cached
  • diff
--- /dev/null
+++ b/sample.ts
@@ -0,0 +1 @@
+const hoge = "hoge";

lint-stagedを実行する

$ npx lint-staged
  ↓ Stashing changes... [skipped]
    → No partially staged files found...
  ✔ Running tasks...
git diff --cached
--- /dev/null
+++ b/sample.ts
@@ -0,0 +1 @@
+const hoge = 'hoge';

ファイル名を合わせておけば設定も自動で読み込んでくれるよう

prettierのsingle-quoteオプションが有効なフォーマットに変換されました

仕事でもこのパターンでやっているが感動したのがgit add -pで追加してた場合でもその差分のみに対してフォーマットをかけてくれる点

いいですね

Huskey

typicode/husky: 🐶 Git hooks made easy

github.com

git pushgit commitの前に処理を差し込めるようになる

GitHub hooksをより扱いやすく(バージョン管理したりできる)するためのライブラリ

中身的にはインストール時に.gith/hooks以下を全部差し替えてるので独自のhooksなどを置いてたりするとなくなるので注意は必要

設定はpackage.jsonhuskyの項目を足すか.huskyrc,.huskyrc.json,.huskyrc.jsに設定を書くかで行える

  • package.json
 },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },

これでCommit時に自動でprettierのフォーマットが走るので何も意識せずフォーマットが統一できます。快適!

  • monorepoの場合

typicode/husky: 🐶 Git hooks made easy

公式にも記述があるがhooksに対して処理を差し込んでいるのでリポジトリのルートでHuskyの設定をするのが良いみたい

複数ディレクトリでそれぞれインストールした場合最後にインストールしたディレクトリの設定に上書きされてしまうもよう

なので最後にインストールしたディレクトリしかフックが発動しないようになる

1つのリポジトリに複数ディレクトリ切ってそれぞれ開発するパターンだとディレクトリごとに微妙に設定変えたいみたいなパターンもあるだろうしどうするのが良いのか

lernaなどを使うのが良いと書いてあるので使ってみてまた後日記事にしたいと思います

まとめ

開発時に整形のコマンドすら打たなくて良いっていう体験は良いですね

ただ、人によってはあえてoffにしたりということもできるのでCIでもチェックはしつつって感じになりますね

nodeのプロジェクトじゃなくてもとりあえずhusky,lint-staged入れてRubyならRubocopだったりの各種lintコマンドを入れておいてもいいのでは?と思いました