Pre-commit hook cepat di Bun dengan Lefthook dan Biome cocok ketika Anda ingin menjaga kualitas kode tanpa membuat proses commit terasa berat. Kombinasi ini bekerja baik untuk proyek JavaScript/TypeScript karena Bun cepat untuk menjalankan script, Lefthook ringan untuk mengelola Git hooks, dan Biome bisa menangani lint sekaligus format dalam satu tool.

Tujuan setup ini sederhana: saat developer menjalankan git commit, hook hanya memeriksa file yang berubah, bukan seluruh repository. Hasilnya, feedback lebih cepat, friction lebih rendah, dan peluang hook di-bypass juga lebih kecil. Namun penting dipahami sejak awal: hook lokal membantu developer experience, tetapi bukan pengganti validasi di CI.

Kapan pendekatan ini tepat dipakai

Setup ini efektif jika tim Anda memiliki kebutuhan berikut:

  • Ingin lint dan format berjalan otomatis sebelum commit.
  • Ingin waktu eksekusi tetap singkat dengan memproses file yang berubah saja.
  • Menggunakan Bun sebagai runtime dan package manager untuk script tooling.
  • Ingin konfigurasi hook yang sederhana dan mudah dibaca tim.

Hook lokal paling berguna untuk mencegah masalah yang murah dideteksi sejak awal, seperti:

  • Formatting tidak konsisten.
  • Error lint dasar.
  • File yang lupa di-format setelah edit.

Sebaliknya, untuk validasi yang lebih mahal atau lebih kritis seperti test suite penuh, build production, type-check seluruh monorepo, atau security scan, tetap jalankan di CI.

Mengapa memilih Bun untuk workflow hook

Alasan utama memilih Bun di konteks ini adalah kecepatan startup dan eksekusi script. Untuk pre-commit hook, biaya terbesar sering bukan logika lint itu sendiri, melainkan akumulasi overhead proses yang dipanggil berkali-kali. Runtime yang ringan membantu mengurangi delay kecil yang terasa pada setiap commit.

Secara praktis, Bun cocok untuk:

  • Menjalankan script lint/format dengan startup cepat.
  • Mengelola dependency dev tooling dalam satu alur.
  • Menyederhanakan command di package.json.

Trade-off-nya, tidak semua tim atau environment sudah memakai Bun secara default. Jika sebagian developer masih memakai Node untuk workflow lain, Anda perlu memastikan dokumentasi setup cukup jelas agar pengalaman antar mesin tetap konsisten.

Arsitektur workflow yang akan dibuat

Kita akan menyiapkan alur berikut:

  1. Developer mengubah beberapa file JavaScript/TypeScript/JSON.
  2. git commit memicu hook dari Lefthook.
  3. Lefthook mengambil daftar file yang di-stage.
  4. Biome dijalankan hanya pada file yang relevan.
  5. Jika ada perbaikan format, file diperbarui dan ditambahkan kembali ke staging area.
  6. Commit lanjut jika semua lolos.

Pola ini penting karena memproses staged files only jauh lebih cepat dibanding menjalankan lint ke seluruh project pada setiap commit.

Struktur repo sederhana

Contoh struktur repository:

my-app/
├─ src/
│  ├─ index.ts
│  └─ utils.ts
├─ package.json
├─ bun.lockb
├─ biome.json
└─ lefthook.yml

Struktur ini cukup untuk kebanyakan project kecil sampai menengah. Jika Anda memakai monorepo, prinsipnya sama, tetapi scope file dan command biasanya perlu disesuaikan per package atau per workspace.

Instalasi dependency

Mulai dari project Bun yang sudah ada. Jika belum ada, Anda bisa menginisialisasi project sesuai kebutuhan tim, lalu pasang dependency berikut:

bun add -d @biomejs/biome lefthook

Setelah itu, siapkan instalasi hook Git milik Lefthook. Cara paling aman adalah memanggil perintah install setelah dependency terpasang, misalnya melalui script prepare agar otomatis aktif setelah install dependency.

Contoh package.json

{
  "name": "my-app",
  "private": true,
  "scripts": {
    "prepare": "lefthook install",
    "lint": "biome check .",
    "format": "biome format --write .",
    "check": "biome check --write ."
  },
  "devDependencies": {
    "@biomejs/biome": "*",
    "lefthook": "*"
  }
}

Beberapa catatan penting:

  • prepare berguna agar hook terpasang ulang setelah bun install.
  • biome check --write praktis untuk pre-commit karena bisa lint sekaligus memperbaiki formatting yang memungkinkan.
  • Hindari terlalu banyak script yang saling memanggil jika tujuan Anda adalah startup yang cepat.

Apakah perlu konfigurasi bunfig?

Untuk use case ini, tidak wajib. Sebagian besar setup pre-commit hook cepat di Bun cukup dengan package.json dan dependency yang benar. Jika tim Anda memang memakai bunfig.toml untuk pengaturan project lain, silakan lanjut, tetapi jangan menambah konfigurasi yang tidak memberi manfaat langsung pada workflow hook.

Konfigurasi Biome yang ringkas

Biome dirancang agar konfigurasi tetap sederhana. Untuk kebanyakan proyek, file konfigurasi minimal sudah cukup.

{
  "$schema": "https://biomejs.dev/schemas/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "space"
  },
  "linter": {
    "enabled": true
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double",
      "semicolons": "asNeeded"
    }
  }
}

Simpan sebagai biome.json. Fokus di tahap awal adalah membuat aturan yang stabil dan tidak terlalu agresif. Jika hook terlalu sering menghasilkan perubahan yang tidak disepakati tim, developer cenderung frustrasi dan akhirnya menonaktifkan hook.

Tip: mulai dari aturan formatter dan lint dasar terlebih dahulu. Tambahkan rule yang lebih ketat secara bertahap setelah tim sudah nyaman dengan alur commit-nya.

Setup Lefthook untuk staged files saja

Bagian terpenting ada di sini: pastikan hook hanya bekerja pada file yang di-stage. Lefthook menyediakan placeholder file yang berubah sehingga command tidak perlu memindai seluruh project.

pre-commit:
  parallel: true
  commands:
    biome:
      glob: "*.{js,jsx,ts,tsx,json,jsonc}"
      run: bunx biome check --write {staged_files} && git add {staged_files}

Simpan sebagai lefthook.yml.

Penjelasan singkat:

  • pre-commit adalah hook yang dijalankan sebelum commit dibuat.
  • glob membatasi file yang diproses ke ekstensi yang relevan.
  • {staged_files} memastikan command hanya menerima file yang sedang masuk commit.
  • git add {staged_files} diperlukan karena formatter dapat mengubah isi file, dan perubahan itu harus dimasukkan lagi ke staging area.

Dengan pola ini, workflow tetap cepat bahkan saat repository mulai membesar, karena biaya pemeriksaan bergantung pada ukuran perubahan commit, bukan ukuran total codebase.

Mengapa pakai bunx di hook?

bunx memudahkan eksekusi binary dari dependency project tanpa path manual. Ini membuat command di hook lebih portabel dan mudah dibaca. Jika tim Anda lebih suka memanggil binary lewat script package.json, itu juga bisa, tetapi sering kali command langsung di Lefthook lebih jelas untuk kebutuhan sederhana seperti ini.

Alur commit developer

Setelah setup selesai, alur kerja sehari-hari menjadi seperti ini:

  1. Developer mengedit file di src/.
  2. Menjalankan git add pada file yang ingin di-commit.
  3. Menjalankan git commit.
  4. Lefthook memanggil Biome hanya untuk file yang di-stage.
  5. Jika Biome bisa memperbaiki formatting, file akan diperbarui dan di-stage ulang.
  6. Jika masih ada error lint yang tidak bisa diperbaiki otomatis, commit gagal dan developer perlu memperbaikinya.

Contoh:

git add src/index.ts
git commit -m "refactor: rapikan util dan formatting"

Jika hook gagal, biasanya output akan menunjukkan file mana yang bermasalah. Developer cukup memperbaiki file tersebut, lalu commit ulang.

Contoh file yang diproses

Misalnya hanya dua file berikut yang berubah:

src/index.ts
src/utils.ts

Saat commit, Biome tidak perlu membaca seluruh folder src atau root project. Ia hanya menerima dua path tadi dari Lefthook. Inilah alasan utama workflow ini terasa responsif.

Menjaga pre-commit hook tetap cepat

Hook yang lambat cenderung dihindari. Beberapa prinsip berikut membantu menjaga performa dan adopsi tim:

1. Hanya jalankan pemeriksaan murah

Pre-commit cocok untuk format dan lint dasar. Hindari menaruh test integration, build penuh, atau scanning berat di tahap ini.

2. Batasi ke staged files

Ini aturan paling penting. Menjalankan biome check . pada setiap commit akan terasa semakin lambat seiring pertumbuhan project.

3. Gunakan satu tool untuk dua kebutuhan jika memungkinkan

Biome berguna karena formatter dan linter ada dalam satu eksekusi. Ini mengurangi jumlah proses yang perlu dijalankan dibanding kombinasi tool terpisah.

4. Hindari rantai script yang terlalu panjang

Jika hook memanggil script A, yang memanggil script B, yang memanggil shell lain lagi, overhead akan menumpuk. Untuk pekerjaan sederhana, command langsung lebih efisien.

5. Simpan rule lint yang realistis

Rule yang terlalu banyak false positive memperlambat tim secara sosial, bukan hanya teknis. Hook yang sering gagal karena alasan yang dianggap remeh akan lebih sering di-skip.

Kapan hook lokal efektif, dan kapan CI tetap wajib

Hook lokal efektif untuk

  • Memberi feedback instan sebelum code masuk history Git.
  • Mencegah formatting berantakan.
  • Mendeteksi masalah lint sederhana sebelum push.
  • Mengurangi noise di pull request.

CI tetap wajib untuk

  • Menegakkan validasi yang tidak boleh dilewati.
  • Menjamin hasil konsisten di environment terkontrol.
  • Menjalankan test suite, build, dan pemeriksaan lint/type-check penuh.
  • Mencegah kasus ketika developer memakai --no-verify atau hook belum terpasang.

Dengan kata lain, hook lokal mempercepat feedback, sedangkan CI menegakkan aturan final. Keduanya saling melengkapi, bukan saling menggantikan.

Batasan dan trade-off pendekatan ini

Walau praktis, ada beberapa batasan yang perlu dipahami:

  • Bisa di-bypass dengan git commit --no-verify.
  • Tergantung environment lokal; jika dependency belum terpasang benar, hook bisa gagal sebelum memeriksa kode.
  • Staged-only check tidak selalu cukup; beberapa masalah baru muncul saat memeriksa project secara keseluruhan.
  • Auto-fix dapat mengubah staging area; ini baik untuk formatting, tetapi perlu dipahami tim agar tidak membingungkan saat commit.

Karena itu, jangan memindahkan seluruh kebijakan quality gate ke pre-commit hook. Jadikan hook sebagai lapisan pertama yang ringan.

Troubleshooting umum

Hook tidak berjalan saat commit

Periksa beberapa hal berikut:

  • Apakah lefthook install sudah dijalankan?
  • Apakah script prepare sempat dieksekusi setelah install dependency?
  • Apakah folder Git hooks di repository sedang dioverride oleh konfigurasi lain?

Coba jalankan ulang:

bun run prepare

Command Biome tidak ditemukan

Biasanya ini terjadi karena dependency belum terpasang atau command di hook tidak memakai runner yang tepat. Jika memakai command langsung ke binary, pastikan path benar. Pendekatan bunx biome ... umumnya lebih aman untuk project lokal.

File sudah diperbaiki, tetapi commit tetap gagal

Pastikan file hasil auto-fix masuk lagi ke staging area. Karena itu contoh konfigurasi di atas menambahkan:

git add {staged_files}

Tanpa langkah ini, hasil format mungkin hanya ada di working tree, bukan di commit.

Hook terasa lambat

Penyebab umum:

  • Command masih memeriksa seluruh project.
  • Terlalu banyak tool dijalankan di satu hook.
  • Hook ikut menjalankan test atau build.
  • Jumlah file yang di-stage memang besar.

Solusinya adalah kembali ke prinsip awal: staged files only, satu tool bila memungkinkan, dan batasi validasi berat ke CI.

Biome memproses file yang tidak relevan

Periksa pola glob di Lefthook. Jika terlalu lebar, hook bisa menangkap file yang seharusnya tidak diproses. Batasi hanya ke ekstensi yang benar-benar dipakai tim.

Contoh setup akhir yang minimal dan praktis

package.json

{
  "name": "my-app",
  "private": true,
  "scripts": {
    "prepare": "lefthook install",
    "check": "biome check --write ."
  },
  "devDependencies": {
    "@biomejs/biome": "*",
    "lefthook": "*"
  }
}

biome.json

{
  "$schema": "https://biomejs.dev/schemas/schema.json",
  "formatter": {
    "enabled": true
  },
  "linter": {
    "enabled": true
  }
}

lefthook.yml

pre-commit:
  commands:
    biome:
      glob: "*.{js,jsx,ts,tsx,json,jsonc}"
      run: bunx biome check --write {staged_files} && git add {staged_files}

Setelah file tersebut ada, jalankan:

bun install

Lalu coba commit perubahan kecil untuk memastikan hook aktif.

Praktik yang direkomendasikan untuk tim

  • Dokumentasikan setup di README onboarding.
  • Pastikan CI menjalankan validasi penuh sebagai jaring pengaman.
  • Mulai dari konfigurasi sederhana, lalu tambah aturan jika benar-benar dibutuhkan.
  • Jangan jadikan pre-commit sebagai tempat semua pemeriksaan masuk.
  • Review waktu eksekusi hook secara berkala jika repo membesar.

Penutup

Pre-commit hook cepat di Bun dengan Lefthook dan Biome adalah solusi praktis untuk meningkatkan kualitas commit tanpa mengorbankan kecepatan kerja developer. Kunci keberhasilannya bukan hanya memilih tool yang cepat, tetapi juga menjaga scope hook tetap kecil: proses file yang di-stage saja, auto-fix yang aman, dan simpan validasi berat untuk CI.

Jika Anda ingin workflow yang terasa ringan namun tetap berguna, kombinasi Bun + Lefthook + Biome adalah titik awal yang solid untuk proyek JavaScript/TypeScript modern.