HuskyからLefthookへ移行してpre-commitを速くする

中級 | 14分 で読める | 2026.06.27

公式ドキュメント

今回やること

この記事では、Husky + lint-staged のpre-commit構成を、Lefthookへ移行する流れを整理します。

pre-commit hookは毎日の開発で何度も動くため、数秒の改善でも体感しやすいです。

CI/CDを組めるだけでなく、ローカルの開発体験まで速くできると、実務でも評価されやすくなります。

前提のHusky構成

よくある構成です。

npm install -D husky lint-staged
npx husky init

.husky/pre-commit:

npx lint-staged

package.json:

{
  "lint-staged": {
    "*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css}": ["prettier --write"]
  }
}

この構成は分かりやすく、最初の導入には向いています。ただし、プロジェクトが大きくなると、npx、Node.jsプロセス起動、直列実行、対象ファイルの扱いで遅く感じることがあります。

Lefthookを入れる

Lefthookを開発依存に追加します。

npm install -D lefthook

初期化します。

npx lefthook install

lefthook.yml を作ります。

pre-commit:
  parallel: true
  commands:
    eslint:
      glob: "*.{ts,tsx,js,jsx}"
      run: npx eslint --fix {staged_files}
      stage_fixed: true
    prettier:
      glob: "*.{ts,tsx,js,jsx,json,md,css}"
      run: npx prettier --write {staged_files}
      stage_fixed: true

parallel: true により、独立したcommandを並列に動かせます。

package managerに合わせる

pnpmを使っているなら、npx より pnpm exec に寄せます。

pre-commit:
  parallel: true
  commands:
    eslint:
      glob: "*.{ts,tsx,js,jsx}"
      run: pnpm exec eslint --fix {staged_files}
      stage_fixed: true
    prettier:
      glob: "*.{ts,tsx,js,jsx,json,md,css}"
      run: pnpm exec prettier --write {staged_files}
      stage_fixed: true

npmなら npx、pnpmなら pnpm exec、bunなら bunx など、プロジェクトのpackage managerに揃えます。

変更ファイルだけ対象にする

pre-commitでは、全ファイルlintではなく、staged filesだけを対象にします。

run: pnpm exec eslint --fix {staged_files}

これにより、変更していない大量のファイルを毎回チェックせずに済みます。

全体チェックはPR CIで行います。

場所対象
pre-commitstaged files
PR CI全体のlint / typecheck / test
main CIbuild / deploy / 重い検証

typecheckをpre-commitに入れすぎない

TypeScriptの tsc --noEmit は、変更ファイルだけで完結しにくく、時間もかかりやすいです。

pre-commitに入れると、commitのたびに待ち時間が増えます。

おすすめ:

pre-commit:
  format
  lint staged files

pre-push or PR CI:
  typecheck
  test
  build

typecheckは重要ですが、実行場所を選びます。

実行時間を測る

移行前後で時間を測ります。

Husky側:

time git commit -m "test"

Lefthook側:

time git commit -m "test"

実際にはcommitを作りたくない場合、テスト用ブランチや小さな変更で確認します。

READMEやPRには、次のように書けます。

## pre-commit高速化

Before:
- Husky + lint-staged
- eslint / prettier を直列気味に実行
- 体感 8-10秒

After:
- Lefthookへ移行
- staged files対象
- eslint / prettierを並列実行
- 体感 3-5秒

数値は必ず自分の環境で測ったものを書きます。

Huskyを削除する

移行後に問題なければ、Husky関連を削除します。

npm uninstall husky lint-staged

.husky/ ディレクトリも不要なら削除します。

ただし、チーム開発では一気に消す前に、READMEやセットアップ手順を更新します。

確認すること:

  • 新規clone後に lefthook install されるか
  • package.jsonのprepare scriptが必要か
  • CIではhookに依存していないか
  • メンバーの環境で同じように動くか

CIではhookに依存しない

pre-commit hookは、ローカルの補助です。CIの代わりではありません。

開発者は --no-verify でhookを飛ばせます。環境差でhookが動かないこともあります。

そのため、PR CIでも必ずチェックします。

- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build

ローカルhookは早くフィードバックするため、CIは最終確認のため、と役割を分けます。

よくある詰まり

症状原因
hookが動かないlefthook install していない
修正されたファイルがstageされないstage_fixed: true がない
ファイル名に空白があると失敗コマンドの渡し方を確認
typecheckが遅いpre-commitではなくPR CIへ移す
Windowsで動かないshell依存の書き方を避ける

移行時は、MacだけでなくWindowsやCI環境も意識します。

まとめ

Husky + lint-staged は導入しやすい構成です。一方、pre-commitの速度や並列実行を重視するなら、Lefthookへの移行は有力です。

  • LefthookはGo製で起動が軽い
  • commandを並列実行しやすい
  • staged filesだけを対象にできる
  • typecheckや重いtestはpre-commitに詰め込みすぎない
  • 移行前後の時間を測る
  • CIでも同じ品質チェックを必ず行う

「hookを入れた」だけでなく、「速くして開発体験を改善した」と説明できる状態を目指します。

参考リソース

次に読む記事

← 一覧に戻る
PR
PR
PR
PR