Belajar Hermes JS Engine - Source Maps & Stack Traces
Episode 10 of 23

Belajar Hermes JS Engine - Source Maps & Stack Traces

Membahas cara menghasilkan source maps untuk bytecode Hermes, membaca stack trace error yang muncul di production, serta best practice penanganan error dan telemetry agar setiap crash bisa dilacak kembali ke baris kode asli.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Episode 9 menutup cerita Hermes di luar mobile: embedding lewat JSI, kompilasi bytecode dengan hermesc, dan realita bahwa Hermes bukan pengganti Node.js. Sekarang kita kembali ke permukaan yang paling sering kalian sentuh di production: saat aplikasi error, dan kalian harus tahu apa yang terjadi dari tumpukan stack trace yang masuk.

Roadmap episode 10: menghasilkan source maps untuk Hermes bytecode, men-debug error stack trace di production, lalu best practice penanganan error dan telemetry. Setelah episode ini, laporan crash bukan lagi teka-teki yang harus ditebak.

Kenapa Hermes Membutuhkan Source Maps

Bundle JavaScript release adalah satu file besar yang sudah di-minify: nama variabel dipersingkat, baris digabung, dan fungsi dipanggil dari offset di dalam file. Di atas itu, Hermes mengkompilasi bundle menjadi bytecode .hbc yang dieksekusi interpreter. Ketika error terjadi, yang bisa dilaporkan interpreter hanyalah posisi di dalam bytecode — bukan baris kode asli yang kalian tulis.

Source map adalah file yang memetakan posisi di kode output kembali ke baris dan kolom di source asli. Inilah jembatan yang mengubah pesan error seperti "TypeError at index.android.bundle:1:4419" menjadi "TypeError at src/screens/Profile.js:23".

Satu hal penting: source map hanya berguna kalau dikirim ke tool observability, bukan disimpan di perangkat. Kalau source map ikut terpasang di aplikasi, isi kode kalian bisa dibaca siapa saja — dan itu melubangi lapisan hardening yang kita bangun di episode 13 nanti.

Menghasilkan Source Maps untuk Hermes Bytecode

Di React Native, pipeline source map berlapis dua. Pertama, Metro menghasilkan source map dari JavaScript. Kedua, hermesc menyempurnakannya agar memetakan offset bytecode ke kode asli. Saat membuat bundle release, aktifkan keduanya. Cara paling mudah mencobanya adalah dari direktori proyek dengan npx react-native bundle --platform android --dev false:

bundle-release-dengan-sourcemap.sh
npx react-native bundle \
  --platform android \
  --dev false \
  --entry-file index.js \
  --bundle-output index.android.bundle \
  --sourcemap-output index.android.map

Untuk memastikan hermesc ikut menghasilkan mapping bytecode, tambahkan flag -output-source-map ke hermesFlags di build.gradle:

hermes-flags-di-build.gradle
react {
  hermesFlags = [
    "-O",
    "-output-source-map",
  ]
}

Kombinasi keduanya menghasilkan dua artefak: bundle bytecode untuk aplikasi, dan source map untuk telemetry. Untuk workload embeddable di luar React Native, hermesc dipanggil langsung dengan flag yang sama:

hermesc-standalone.sh
hermesc -O -emit-binary -output-source-map -out worker.hbc worker.js

Membaca Stack Trace Hermes di Production

Ketika bug lolos ke production, telemetry menerima sesuatu seperti ini:

stack-trace-mentah.txt
Error: Gagal mengirim pesanan
    at submitOrder (index.android.bundle:1:4419)
    at CheckoutScreen.<anonymous> (index.android.bundle:1:8877)
    at onPress (index.android.bundle:1:12033)
    at HermesInternal.jsFunctionCall (native)
    at executeOnJSThread (native)

Frame HermesInternal dan executeOnJSThread adalah noise dari dalam runtime — abaikan saja. Yang menarik adalah tiga frame teratas: masing-masing berisi nama fungsi yang sudah di-minify dan offset bytecode. Nomor offset inilah yang harus dipetakan source map untuk menemukan lokasi asli.

Kalau stack trace kalian malah kosong atau hanya berisi (native), periksa apakah flag -output-source-map benar-benar aktif di release build. Tanpa mapping bytecode, tool seperti Sentry atau Crashlytics tidak akan bisa me-rewrite stack trace tersebut.

Info

Pastikan versi source map yang diunggah sama persis dengan bytecode yang terpasang di aplikasi. Kalau build berubah tanpa mengunggah source map baru, hasil symbolication akan salah arah — lebih buruk daripada tidak punya source map sama sekali.

Symbolication: Memetakan Offset ke Kode Asli

Proses menerjemahkan stack trace mentah menjadi baris kode asli disebut symbolication. Untuk Hermes, hermesc punya mode khusus yang menerima source map dan stack trace, lalu mengeluarkan versi yang sudah diterjemahkan:

symbolicate-dengan-hermesc.sh
hermesc -symbolicate -output-source-map index.android.map < stack.txt

Pipeline yang lebih umum di React Native: unggah source map ke layanan telemetry saat release (misalnya dengan sentry-cli dan perintah upload-sourcemaps), lalu biarkan layanan tersebut melakukan symbolication otomatis untuk setiap stack trace yang masuk. Perhatikan urutan upload: source map harus terunggah sebelum aplikasi rilis ke pengguna.

Selain stack trace error, jangan lupa menangkap konteks: versi aplikasi, versi Hermes, model perangkat, dan OS. Konteks inilah yang membedakan "banyak user error" dengan "satu device bermasalah".

Best Practice Penanganan Error dan Telemetry

Penanganan error yang baik dimulai dari satu titik masuk. Di React Native, kita bisa mengganti global handler untuk menangkap error yang tidak tertangkap sebelum benar-benar fatal:

JSglobal-error-handler.js
const previousHandler = ErrorUtils.getGlobalHandler();
 
ErrorUtils.setGlobalHandler((error, isFatal) => {
  Telemetry.captureException(error, {
    extra: { isFatal },
    tags: { build: "2026-08-03" },
  });
  previousHandler(error, isFatal);
});

Selanjutnya, beberapa kebiasaan yang membuat telemetry benar-benar berguna:

  • Satu cara memicu error: semua operasi yang berpotensi gagal dipanggil lewat helper try/catch yang sama, supaya format laporannya konsisten.
  • Breadcrumbs: catat langkah user sebelum error, misalnya "masuk halaman checkout", supaya stack trace punya konteks.
  • Deduplikasi: kelompokkan error berdasarkan fingerprint stack trace hasil symbolication, bukan berdasarkan pesan mentah, supaya volume alert tidak menyesatkan.
  • Jangan kirim data sensitif: redaksi parameter yang memuat token atau data pribadi sebelum dikirim, sebagaimana dibahas di episode 13.

Source map yang rapi, stack trace yang ter-symbolicate, dan handler yang konsisten mengubah debugging production dari kegiatan menebak menjadi kegiatan membaca.

Penutup

Kalian sekarang punya rantai lengkap: source map dihasilkan saat build, diunggah ke telemetry, lalu dipakai untuk menerjemahkan setiap stack trace Hermes yang masuk. Dengan global error handler dan kebiasaan telemetry yang baik, setiap crash punya jalur pelacakan yang jelas kembali ke baris kode asli.

Inti yang harus dibawa pulang:

  • Source map memetakan offset bytecode Hermes ke baris kode asli, dan harus diunggah ke tool observability, bukan dikirim ke perangkat.
  • Aktifkan source map di dua lapis: Metro dan flag -output-source-map dari hermesc.
  • Frame HermesInternal dan (native) di stack trace adalah noise runtime yang bisa diabaikan.
  • Gunakan hermesc -symbolicate atau layanan telemetry untuk menerjemahkan stack trace production.
  • Tangkap konteks (versi, device, breadcrumbs) dan redaksi data sensitif sebelum laporan masuk ke telemetry.

Di episode 11 berikutnya kita merapikan rumah: configuration management & build validation — cara menyimpan konfigurasi Hermes agar build reproducible, memvalidasi output di CI, dan mengintegrasikan semuanya dengan linting serta release pipeline. Sampai jumpa!

Belajar Hermes JS Engine - Source Maps & Stack Traces | Belajar Hermes JS Engine