はじめに
以前こちらの記事で ESLint と Prettier を導入しました 👇
かなり快適になったのですが、shadcn/ui のコンポーネントを追加したあと、コマンドを手動で実行しないままコミットすると、Lint ルールに反したコードが混ざってしまう問題がありました。
毎回コマンドを叩くのは手間なので、Husky を導入してコミット時に自動で Lint されるようにしました。
リポジトリ
私のフロントエンド設定テンプレを置いておきます。
本記事の内容も含みますが、リポジトリは今後も更新される可能性があります。
使用技術
主なパッケージのバージョンです。
- Husky: v9.1.7
- lint-staged: v16.2.6
- Vite: v7.2.2
- React: v19.2.0
- TypeScript: v5.9.3
- ESLint: v9.39.1
- Prettier: v3.6.2
導入手順
1. Huskey を導入する
Automatically lint your commit messages, code, and run tests upon committing or pushing.
npm install --save-dev husky
次のコマンドで Husky を初期化します。
.husky/ 内に pre-commit スクリプトが作成されます。
ここに書いたコマンドがコミット時に実行されます。
npx husky init
.husky はプロジェクトルートに置く必要があります。
プロジェクトルートにない場合、Husky は動作しません。
モノリポ構成などの理由で package.json がプロジェクトルートにない場合の対処法は後で紹介します。
2. lint-staged を導入する
Run tasks like formatters and linters against staged git files and don't let 💩 slip into your code base!
npm install --save-dev lint-staged
.husky/pre-commit を次のように書き換えます。
npx lint-staged
package.json に次のように追記します。
{
// ...
+ "lint-staged": {
+ "*.{js,jsx,ts,tsx}": [
+ "eslint --fix",
+ "prettier --write"
+ ],
+ }
}
動作確認
; なしの JavaScript コードを git commit すると整形されてコミットされます。
console.log('Hello, world!\n')
✔ Backed up original state in git stash (3227603)
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
[main e2b3f0a] test
1 file changed, 1 insertion(+)
create mode 100644 husky-test.js
不要なインポートのあるファイルを git commit すると eslint --fix では直せず失敗します。
✔ Backed up original state in git stash (a031c8e)
⚠ Running tasks for staged files...
❯ package.json — 1 file
❯ *.{js,jsx,ts,tsx} — 1 file
✖ eslint --fix [FAILED]
◼ prettier --write
↓ *.{json,md} — no files
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...
✖ eslint --fix:
/home/kamata-k/workspace/frontend-sample/src/main.tsx
1:23 error 'useState' is defined but never used @typescript-eslint/no-unused-vars
✖ 1 problem (1 error, 0 warnings)
✖ eslint --fix failed to spawn:
Command failed with exit code 1: eslint --fix /home/kamata-k/workspace/frontend-sample/src/main.tsx
undefined
husky - pre-commit script failed (code 1)
トラブルシューティング
モノリポ構成であるなどの理由で package.json がルートにない場合もあると思います。
次のようなディレクトリ構成を考えます。
frontend/ に ESLint や Prettier の設定があるケースです。
repo/
└── frontend/
├── .prettiertc
├── eslint.config.js
└── package.json
プロジェクトルートで npm init し、package.json を作ります。
repo/
├── frontend/
| ├── .prettiertc
| ├── eslint.config.js
| └── package.json
└── package.json
プロジェクトルートで Husky と lint-staged をインストールし、それぞれの package.json を次のように設定します。
{
// ...
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
+ "lint": "eslint . --fix",
+ "format": "prettier . --write",
"preview": "vite preview"
},
// ...
}
{
// ...
+ "lint-staged": {
+ "frontend/**/*.{js,jsx,ts,tsx}": [
+ "npm run --prefix frontend lint",
+ "npm run --prefix frontend format"
+ ]
+ }
}
--prefix オプションでサブディレクトリの package.json を指定することで、frontend/ の ESLint や Prettier を実行できます。
最終的なディレクトリ構成は次のようになるはずです。
repo/
├── .husky
| └──pre-commit
├── frontend/
| ├── .prettiertc
| ├── eslint.config.js
| └── package.json
└── package.json
おわりに
ストレスが軽減されました。あと 90 年は生きられる 🐻