Pre-commit hooks dengan Lefthook berguna untuk menangkap masalah yang sebenarnya bisa diketahui lebih awal, seperti lint gagal, format belum rapi, atau test ringan yang rusak. Tujuannya bukan menggantikan CI, tetapi memindahkan pemeriksaan yang murah dan cepat ke mesin developer agar kegagalan tidak baru terlihat setelah push atau membuka pull request.
Masalah yang sering terjadi di tim adalah pipeline CI gagal karena hal-hal sederhana: file belum diformat, aturan ESLint dilanggar, atau perubahan kecil memutus test unit tertentu. Jika pemeriksaan seperti ini dijalankan saat pre-commit, feedback datang dalam hitungan detik, bukan menit. Untuk kebutuhan itu, Lefthook adalah salah satu opsi yang praktis karena fokus pada pengelolaan Git hooks dengan konfigurasi yang jelas dan ringan.
Mengapa pre-commit hook relevan sebelum CI
CI tetap penting sebagai sumber verifikasi utama di lingkungan yang konsisten. Namun, ada kelas error yang tidak perlu menunggu CI:
- Lint error yang deterministik dan cepat diperiksa.
- Format code yang bisa diperbaiki otomatis sebelum commit.
- Subset test yang murah dijalankan, misalnya test terkait file yang berubah.
- Validasi dasar seperti type check parsial atau pemeriksaan file yang staged.
Dengan memindahkan pengecekan murah ke lokal, Anda mengurangi antrean CI yang sia-sia dan mempercepat siklus review. Ini sangat terasa pada repository yang banyak contributor atau pipeline yang memakan waktu cukup lama.
Prinsip penting: pre-commit hook sebaiknya hanya menjalankan task yang cepat, deterministik, dan relevan dengan perubahan lokal. Hook yang terlalu berat akan sering di-bypass.
Kapan Lefthook cocok digunakan
Lefthook cocok ketika tim ingin menstandarkan Git hooks tanpa menulis shell script yang panjang dan rapuh. Tool ini berguna jika Anda ingin:
- Mengelola hook lewat satu file konfigurasi.
- Menjalankan beberapa command secara konsisten di semua mesin developer.
- Menggunakan placeholder file staged atau file yang berubah.
- Mengintegrasikan hook dengan npm, pnpm, atau toolchain JavaScript/TypeScript lain.
Jika proyek Anda kecil dan hanya membutuhkan satu command sederhana, shell script biasa mungkin cukup. Namun ketika aturan mulai bertambah, konfigurasi yang terstruktur akan lebih mudah dirawat.
Trade-off: kualitas lebih awal vs kecepatan developer
Pre-commit hook selalu punya biaya: setiap commit menjadi sedikit lebih lambat. Karena itu, pemilihan task sangat menentukan keberhasilannya.
Task yang aman dijalankan di pre-commit
- Formatter pada file staged, misalnya Prettier.
- Linter pada file yang berubah, misalnya ESLint.
- Test ringan yang ditargetkan ke area perubahan.
- Pemeriksaan file staged seperti ukuran file, conflict marker, atau validasi dasar JSON/YAML bila perlu.
Task yang biasanya lebih cocok di pre-push atau CI
- Seluruh test suite yang memakan waktu lama.
- Build produksi penuh.
- Type check penuh untuk monorepo besar jika durasinya signifikan.
- Integrasi ke service eksternal.
Aturan praktisnya sederhana: jika command sering butuh waktu lama atau hasilnya tidak stabil antar mesin, jangan paksa masuk ke pre-commit.
Instalasi Lefthook di proyek JavaScript/TypeScript
Integrasi Lefthook biasanya melibatkan dua langkah: memasang paketnya dan menginisialisasi Git hooks agar repository memakai konfigurasi yang Anda simpan.
Contoh dengan npm
npm install -D lefthookTambahkan script agar setup hook mudah dijalankan setelah install dependency:
{
"scripts": {
"prepare": "lefthook install",
"lint": "eslint .",
"format": "prettier --write .",
"test": "vitest run"
}
}Dengan pola ini, hook akan dipasang saat dependency project disiapkan. Jika tim memakai package manager lain, pola dasarnya tetap sama.
Contoh dengan pnpm
pnpm add -D lefthookLalu tambahkan script:
{
"scripts": {
"prepare": "lefthook install"
}
}Pastikan anggota tim menjalankan install dependency seperti biasa agar Git hooks ikut terpasang.
Contoh konfigurasi Lefthook untuk ESLint, Prettier, dan test ringan
Berikut contoh konfigurasi pre-commit hooks dengan Lefthook untuk proyek JavaScript/TypeScript. Fokusnya adalah menjalankan task hanya pada file yang relevan agar tetap cepat.
pre-commit:
parallel: true
commands:
prettier:
glob: "*.{js,jsx,ts,tsx,json,md,yml,yaml}"
run: npx prettier --write {staged_files}
stage_fixed: true
eslint:
glob: "*.{js,jsx,ts,tsx}"
run: npx eslint --fix {staged_files}
stage_fixed: true
test-related:
glob: "*.{js,jsx,ts,tsx}"
run: pnpm test -- --runRelatedTests {staged_files}Ada beberapa hal penting dari konfigurasi di atas:
- glob membatasi command hanya untuk tipe file tertentu.
- {staged_files} membuat command berjalan pada file yang sedang akan di-commit, bukan seluruh repository.
- stage_fixed: true berguna saat formatter atau linter memperbaiki file otomatis, lalu perubahan hasil perbaikan ikut dimasukkan kembali ke staging area.
- parallel: true bisa mempercepat eksekusi, tetapi tetap perhatikan apakah command Anda aman dijalankan bersamaan.
Untuk bagian test, contoh di atas menunjukkan pendekatan yang umum: gunakan kemampuan test runner untuk menargetkan test yang berhubungan dengan file yang berubah. Detail flag bisa berbeda tergantung runner yang dipakai, jadi sesuaikan dengan tool di proyek Anda. Jika dukungan related tests tidak ada atau terlalu lambat, lebih baik pindahkan test tersebut ke pre-push atau CI.
Alternatif yang lebih konservatif
Jika test terkait file berubah masih terlalu mahal, mulailah dari formatter dan linter saja:
pre-commit:
commands:
prettier:
glob: "*.{js,jsx,ts,tsx,json,md}"
run: npx prettier --write {staged_files}
stage_fixed: true
eslint:
glob: "*.{js,jsx,ts,tsx}"
run: npx eslint --fix {staged_files}
stage_fixed: trueIni sering menjadi baseline yang aman untuk hampir semua tim frontend atau full-stack JavaScript.
Cara memilih task lokal yang tepat
Jangan memasukkan semua pemeriksaan ke pre-commit. Pilih berdasarkan tiga pertanyaan:
- Apakah task ini cepat? Targetkan hitungan detik, bukan menit.
- Apakah task ini deterministik? Hasil seharusnya konsisten di mesin developer dan CI.
- Apakah task ini relevan terhadap perubahan lokal? Jika bisa dipersempit ke file staged, itu kandidat bagus.
Contoh keputusan yang masuk akal:
- Ya di pre-commit: Prettier, ESLint file staged, unit test kecil yang ter-target.
- Ya di pre-push: test unit lebih luas, type check yang masih cukup cepat.
- Tetap di CI: build penuh, e2e, integration test, security scan, dan validasi lintas layanan.
Integrasi dengan script npm atau pnpm
Sebaiknya command hook tidak menulis logika yang terlalu banyak langsung di konfigurasi. Letakkan logika utama di script package manager agar lebih mudah dijalankan ulang secara manual.
{
"scripts": {
"prepare": "lefthook install",
"lint:staged": "eslint --fix",
"format:staged": "prettier --write",
"test:related": "vitest run"
}
}Lalu panggil script tersebut dari Lefthook jika memang cocok. Keuntungannya:
- Developer bisa menjalankan command yang sama tanpa harus memicu hook.
- Konfigurasi lebih mudah dipindah atau diubah.
- Debugging lebih sederhana karena command utama sudah ada sebagai script terpisah.
Namun, untuk command yang membutuhkan placeholder seperti {staged_files}, sering kali tetap lebih jelas jika diletakkan langsung di konfigurasi Lefthook.
Perbandingan singkat Lefthook dan Husky
Lefthook dan Husky sama-sama dipakai untuk mengelola Git hooks, tetapi pendekatannya sedikit berbeda.
Kapan memilih Lefthook
- Anda ingin konfigurasi hook yang terpusat dan ringkas.
- Anda ingin mendefinisikan beberapa command dengan struktur yang jelas.
- Anda ingin pola yang mudah dibaca tim tanpa banyak shell script manual.
Kapan Husky masih masuk akal
- Tim Anda sudah lama memakainya dan tidak punya masalah berarti.
- Anda lebih nyaman mengelola hook sebagai script file per hook.
- Setup proyek sudah stabil dan migrasi tidak memberi manfaat nyata.
Tidak perlu migrasi hanya demi ganti tool. Jika Husky yang sekarang sudah cepat, jelas, dan tidak menyulitkan tim, tetap pakai juga tidak masalah. Pilih tool yang paling mudah dirawat oleh tim Anda.
Praktik tim agar hook tidak dibenci developer
1. Fail fast
Jalankan pemeriksaan yang paling murah lebih dulu. Misalnya formatter dan linter sebelum test. Jika lint sudah gagal, tidak ada manfaat menjalankan test ringan berikutnya.
2. Output harus jelas
Hindari command yang menghasilkan log berlebihan tanpa konteks. Developer harus bisa langsung tahu file mana yang gagal dan langkah apa yang perlu dilakukan. Jika memungkinkan, tampilkan pesan yang actionable.
3. Jaga durasi tetap pendek
Hook yang lambat hampir pasti akan mendorong orang mencari cara melewatinya. Lebih baik coverage pre-commit lebih sempit tetapi konsisten dipakai, daripada sangat lengkap namun sering di-skip.
4. Skip hook secara terkontrol
Ada situasi khusus ketika hook perlu dilewati, misalnya saat melakukan eksperimen lokal atau recovery commit. Git menyediakan cara untuk melewati hook, tetapi ini sebaiknya menjadi pengecualian, bukan kebiasaan harian. Jika tim terlalu sering melewati hook, itu tanda bahwa hook terlalu berat atau terlalu banyak false positive.
5. Dokumentasikan tujuan tiap hook
Tim perlu tahu mengapa sebuah command ada di pre-commit, apakah ia memperbaiki file otomatis, dan kapan seharusnya dipindahkan ke pre-push atau CI. Dokumentasi singkat di README biasanya cukup.
Kesalahan umum saat menerapkan pre-commit hook
- Menjalankan seluruh test suite di pre-commit. Ini hampir selalu terlalu lambat.
- Menjalankan lint ke seluruh repository. Gunakan file staged atau file yang berubah bila memungkinkan.
- Tidak me-restage file yang diperbaiki otomatis. Hasil formatter bisa tidak ikut ke commit jika konfigurasi tidak menangani staging ulang.
- Mengandalkan hook sebagai satu-satunya verifikasi. CI tetap dibutuhkan sebagai pemeriksaan final.
- Konfigurasi terlalu kompleks. Mulai dari sedikit aturan yang jelas, lalu tambah hanya jika benar-benar perlu.
Tips debugging saat hook tidak berjalan seperti yang diharapkan
Periksa apakah hook benar-benar terpasang
Jika setelah install dependency hook tidak aktif, cek apakah langkah instalasi Lefthook sudah dijalankan. Pada banyak proyek, ini diotomatisasi lewat script prepare.
Jalankan command secara manual
Jika command di hook gagal, jalankan command yang sama langsung di terminal. Ini membantu membedakan apakah masalah ada di Lefthook, di shell environment, atau di tool seperti ESLint/Prettier/test runner.
Perhatikan placeholder file
Jika command menerima daftar file dari staging area, pastikan tool yang dipanggil memang mendukung menerima banyak path sekaligus. Beberapa command perlu penyesuaian kecil pada urutan argumen.
Cek perilaku auto-fix
Jika file diperbaiki otomatis tetapi hasilnya tidak ikut ke commit, pastikan konfigurasi memang menambahkan kembali perubahan hasil fix ke staging area.
Rekomendasi implementasi yang realistis
Untuk banyak proyek JavaScript/TypeScript, strategi awal yang sehat adalah:
- Aktifkan Prettier pada file staged.
- Aktifkan ESLint --fix pada file staged.
- Tambahkan test ringan hanya jika benar-benar cepat dan stabil.
- Biarkan type check penuh, build, dan test besar tetap di CI atau pre-push.
Pendekatan ini memberi manfaat cepat tanpa terlalu mengganggu ritme commit developer.
Penutup
Pre-commit hooks dengan Lefthook efektif untuk mencegah kegagalan CI yang sebenarnya bisa ditangkap lebih awal di mesin lokal. Nilai utamanya bukan pada banyaknya pemeriksaan, tetapi pada pemilihan task yang cepat, jelas, dan relevan terhadap perubahan yang sedang di-commit.
Jika Anda menerapkannya, mulai dari yang kecil: formatter dan linter pada file staged. Setelah itu, evaluasi apakah test ringan layak ditambahkan. Selama hook tetap cepat dan output-nya jelas, developer cenderung menerima proses ini sebagai pengaman yang membantu, bukan hambatan tambahan.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!