以前の記事で、コードを綺麗に整形するためのeslintprettierを説明しました。
しかし一々コードを書いたらリンターとフォーマッターを実施するためにnpmコマンドを実行するのはめんどくさいですよね。複数人で開発している場合はフォーマッターかけることを忘れてしまう人も出てきてしまうため、その後他の人がnpmコマンドでフォーマッターを実施したら忘れてしまった人のフォーマッター差分も発生してしまいプルリクなどが見にくくなってしまいます。
そうならないためにも逐一コードの整形はやっていきたいですね。と言うことでcommitやpush時強制的にコードを綺麗にしましょう!

  • この記事はhuskyとlint-stagedに焦点を当てるため、eslint,prettierの説明はしません。
  • 説明を簡素化させるためにprettierのみinstallしeslintは使用しない

目次

環境

Node: 16.13.2

{
  "devDependencies": {
    "husky": "^8.0.1",
    "lint-staged": "^13.0.3",
    "prettier": "^2.7.1"
  }
}

今回の完成形

{
  "name": "project-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.ts",
  "scripts": {
    "pre-commit": "lint-staged",
    "prepare": "husky install"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "husky": "^8.0.1",
    "lint-staged": "^13.0.3",
    "prettier": "^2.7.1"
  },
  "lint-staged": {
    "**/*.ts": [
      "prettier --write"
    ]
  }
}

ディレクトリ構造

root
┗ .husky
  ┗ pre-commit
┗ index.ts
┗ package.lock.json
┗ package.json

下準備

まずはnpmプロジェクト作成

$ npm init

$ git init

今回使用するパッケージinstall

$ npm i -D husky lint-staged prettier

huskyでpre-commitの設定

まずはhuskyの公式ドキュメントに沿って設定を行なっていきます。

  1. huskyを初期化
npx husky install

npm iした時に自動的に設定されるようにpackage.jsonに以下を追加  

{
  "scripts": {
    "prepare": "husky install"
  }
}

こうすることで自分以外がこのプロジェクトを使用する時にnpm iするだけでセットアップできます。

  1. prettierの整形コマンド設定
{
  "scripts": {
    "prepare": "husky install",
    "pre-commit": "prettier --write \"**/*.{ts,js}\""
  }
}
  1. huskyでpre-commitの設定
npx husky add .husky/pre-commit "npm pre-commit"

huskyのみ設定で検証  

huskyだけの設定が完了しました。では適当なファイルを作成してみましょう。

// index.ts
const hello = (): void => {
  console.log("hello")
};

hello();

このファイルはconsole.logの後にセミコロン(;)が入っていません

このファイルをaddしてコミットしてみましょう

git add index.ts
git commit -m 'husky only index.ts'

あれ?prettierで整形はされていますが、整形された変更点はコミットされていませんね。
理由は以下の通りです。

  1. 整形されていないindex.tsをaddする
  2. commitしてpre-commit(prettier)が走る
  3. prettierでindex.tsが整形され変更が入る
  4. addされているファイルがコミットされる。この時prettierで整形されたファイルはaddされていないのでstagedにいる整形前のindex.tsがコミットされる

んー求めているものではないですね。この時にlint-stagedの出番です。

lint-stagedを導入してpre-commitの設定

lint-stagedはgitのstagedにいるファイルに対して特定の処理を実施してくれます。

Linting makes more sense when run before committing your code.

公式でも記載のある通り今回の実施したいことに最適ですね。

  1. lint-stagedの設定 package.jsonに以下の設定を追加
{
  "lint-staged": {
    "**/*.{ts,js}": [
      "prettier --write"
    ]
  }
}

pre-commitのscriptsをlint-stagedを通すようにします

{
  "scripts": {
    "prepare": "husky install",
    "pre-commit": "list-staged" // ここを変更
  }
}

設定はこれだけです。

  1. lint-stagedを導入した検証

では、index.tsを整形前に戻してadd, commitしてみましょう。

git add index.ts
git commit -m 'husky, lint-staged'

今度はしっかり整形された状態でコミットされましたね!

終わりに

今回はhuskyとlint-stagedを使用してgit-hookを簡単にセットアップしました。これで書き方の論争が起こらなくなり、プルリクなども見やすくなりますね。
2022年現在はこの2つがjavascript,typescriptのpre-commitのデファクトスタンダードですが、そのうち他のものが出てきてそっちの方がいいとなるかもしれませんね。エンジニアは常に技術を追っていかないといけないので大変ですね…それが楽しいところもあるのですが

参考