Belajar Hermes JS Engine - Hermes di Node.js & Edge Runtime
Episode 9 of 23

Belajar Hermes JS Engine - Hermes di Node.js & Edge Runtime

Membahas Hermes sebagai embeddable engine di luar mobile: status dukungan Node.js, use case serverless dan edge yang diuntungkan cold start, cara embedding Hermes secara custom, serta perbedaan strategi optimasi antara runtime mobile dan server.

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

Pendahuluan

Hingga episode 8, dunia kita adalah mobile: React Native, gradle, dan Podfile. Tapi Hermes lahir sebagai engine yang embeddable — ia bisa disuntikkan ke produk apa pun yang butuh eksekusi JavaScript cepat dan hemat. Itu membuka pertanyaan besar: bagaimana kalau kita bawa Hermes ke server, ke serverless, atau ke edge runtime?

Episode ini menjawab pertanyaan itu dengan jujur: apa status dukungan Hermes untuk Node.js, kapan Hermes benar-benar menguntungkan di lingkungan serverless dan edge, bagaimana cara embedding Hermes secara custom, dan apa perbedaan fundamental strategi optimasi antara runtime mobile dan server. Tidak semua cerita tentang Hermes di server berujung pada "pakai saja" — dan memahami kenapa justru membuat kalian lebih bijak memilih engine.

Hermes sebagai Embeddable Engine

Desain Hermes sejak awal menargetkan embedding: ia bukan aplikasi mandiri seperti Node.js, melainkan pustaka yang dipanggil oleh host. Di tingkat C++, host membuat runtime lewat API dari framework JSI (JavaScript Interface):

Linuxembed-hello.cpp
#include <hermes/hermes.h>
#include <jsi/jsi.h>
 
using namespace facebook::jsi;
 
int main() {
  auto runtime = HermesRuntime::make();
  auto result = runtime->evaluateJavaScript(
      makeString(*runtime, "1 + 1;"),
      "inline.js");
  return result.asNumber() == 2 ? 0 : 1;
}

Contoh di atas menginstansiasi satu HermesRuntime, mengeksekusi ekspresi kecil, dan memeriksa hasilnya. Pola inilah yang dipakai React Native lewat JSI — dan pola yang sama bisa dipakai produk lain: aplikasi desktop, tooling, game engine, atau runtime server. Karena Hermes mengonsumsi memori kecil dan tidak bergantung pada banyak dependency sistem, ia nyaman di-embed ke hampir semua produk.

Catatan penting: embedding bukan berarti membangun ulang Node.js. Kalian memilih API yang benar-benar dipakai workload, menyediakannya lewat binding, dan membiarkan sisanya tidak ada — footprint yang kecil justru lahir dari kedisiplinan ini.

Hermes dan Node.js: Realita yang Jujur

Bagian ini perlu kejujuran: Hermes bukan drop-in replacement untuk Node.js. Node.js adalah ekosistem lengkap — fs, net, http, path, dan ratusan modul built-in yang tidak ada di Hermes core. Menjalankan aplikasi Express di atas Hermes tidak akan jalan begitu saja, karena API yang dipakai aplikasi tidak tersedia di runtime.

Yang bisa dilakukan dengan Hermes di sisi server adalah dua hal: memakai hermesc sebagai compiler bytecode untuk workload yang kita kendalikan sendiri, atau melakukan custom embedding dengan host kita menyediakan binding yang dibutuhkan. Untuk workload Node.js konvensional yang mengandalkan ekosistem npm penuh, engine seperti V8 (Node.js), JavaScriptCore (Bun), atau V8 lagi (Deno) tetap pilihan utama.

Jadi jangan buru-buru mengganti engine aplikasi Node.js kalian dengan Hermes. Evaluasi dimulai dari pertanyaan workload: apakah yang lebih penting adalah peak performance di bawah beban tinggi (V8 unggul), atau kecepatan mulai dan memory kecil (Hermes unggul)?

Use Cases Serverless dan Edge

Di dunia serverless dan edge, ceritanya berbeda. Fungsi serverless dijalankan on-demand: setiap invoke baru bisa berarti menyalakan runtime dari nol. Di sinilah kekuatan Hermes terlihat:

  • Cold start cepat: bytecode precompiled tidak perlu di-parse ulang, jadi eksekusi pertama jauh lebih singkat.
  • Memory kecil: fungsi edge biasanya dibatasi memory ketat (misalnya 128 MB), dan footprint Hermes membantu tetap di bawah batas.
  • AOT alami: bytecode HBC adalah bentuk AOT — cocok untuk fungsi yang jalannya sebentar dan sering dimulai ulang.

Trade-off-nya juga jelas: tanpa JIT, throughput di bawah beban sustained tidak sebaik V8, dan model threading Hermes yang simpel berarti workload paralel harus dipecah ke banyak instance. Karena itu Hermes paling masuk akal untuk fungsi yang pendek, sering dipanggil, dan memory-bound, bukan untuk layanan yang menangani koneksi panjang dengan CPU intensif.

Info

Runtime edge utama saat ini memakai engine yang berbeda-beda dengan trade-off masing-masing. Evaluasi Hermes untuk edge dengan benchmark pada workload kalian sendiri: ukur cold start dan p95 latency, bukan sekadar membandingkan spesifikasi engine.

Embedding Hermes dengan Snapshot dan Bytecode

Untuk memanfaatkan Hermes di server, workflow khasnya adalah: kompilasi JavaScript menjadi bytecode saat build, lalu muat bytecode itu saat runtime. Kompilasi dilakukan dengan hermesc:

kompilasi-bytecode.sh
hermesc -emit-binary -O -out worker.hbc worker.js

Hasilnya worker.hbc adalah file binary yang siap di-load. Untuk aplikasi besar, Hermes juga mendukung snapshot — kondisi runtime yang sudah diisi nilai awal dan diserialisasi, sehingga inisialisasi berikutnya nyaris instan. Ini teknik yang sama yang membuat startup React Native cepat, dan di sisi server ia mengurangi latensi setiap instance fungsi baru.

Karena serverless biasanya memakai arsitektur banyak-instance, keuntungan snapshot berlipat: setiap instance baru lahir dari snapshot yang sama, memuat lebih cepat, dan langsung siap melayani.

Praktik: Edge Function dengan Hermes

Setelah memahami pola dasar embedding, mari kita rangkai satu contoh nyata: sebuah edge function yang memuat worker.hbc, menyediakan binding send lewat host function, lalu mengeksekusi kode yang sudah dikompilasi:

Linuxedge-worker.cpp
#include <hermes/hermes.h>
#include <jsi/jsi.h>
#include <iostream>
 
using namespace facebook::jsi;
 
void run(HermesRuntime& rt) {
  auto global = rt.global();
  auto send = Function::createFromHostFunction(
      rt,
      PropNameID::forAscii(rt, "send"),
      1,
      [&rt](Runtime&, const Value&, const Value* args, size_t) {
        std::cout << args[0].getString(rt).utf8(rt) << std::endl;
        return Value::undefined();
      });
  global.setProperty(rt, "send", send);
  rt.evaluateJavaScript(
      makeString(rt, "send('halo edge');"),
      "worker.hbc");
}

Perhatikan polanya: runtime dibuat sekali, binding disuntikkan ke global, lalu payload dijalankan lewat evaluateJavaScript. Karena worker.hbc sudah dikompilasi saat build, tidak ada parsing saat request masuk — itulah yang membuat cold start terasa instan.

Warning

Prinsip keamanan saat embedding: hanya ekspos binding yang benar-benar dibutuhkan workload. Setiap host function yang kalian sediakan adalah permukaan serangan — di edge, kode kalian berjalan dekat dengan input user, jadi validasi argumen di setiap binding sebelum diproses.

Perbandingan Optimasi Mobile vs Server

Strategi optimasi yang benar bergantung di mana engine berjalan. Inilah perbandingan yang perlu diingat:

AspekMobile (React Native)Server / Edge
Prioritas utamaStartup cepat dan memori rendahCold start dan latensi invoke
Bentuk kodeBytecode HBC dari bundleBytecode HBC atau snapshot
Profil bebanIntermiten, dipakai-userOn-demand, banyak instance
ConcurrencySatu UI thread + workersBanyak instance paralel
Kekuatan HermesFootprint kecil, parse nolAOT, loading instan
KelemahanTanpa JIT, peak CPU terbatasTanpa JIT, workload sustained kurang optimal

Kuncinya: Hermes mengorbankan peak performance (yang dimiliki engine ber-JIT seperti V8) demi kepastian — startup yang cepat, memory yang kecil, dan perilaku yang bisa diprediksi. Di mobile, kepastian itu lebih berharga. Di server dengan beban sustained, engine ber-JIT sering kali menang telak.

Penutup

Kalian sekarang melihat Hermes dari sisi embeddable: API C++ untuk membuat runtime, hermesc untuk mengompilasi bytecode, snapshot untuk loading instan, dan realita bahwa Hermes bukan pengganti Node.js. Kalian juga paham kapan Hermes pantas dipertimbangkan di serverless dan edge — fungsi pendek, sering dipanggil, dan memory-bound — serta perbandingan jujur dengan runtime server mainstream.

Inti yang harus dibawa pulang:

  • Hermes adalah engine embeddable lewat JSI dan API C++, bukan pengganti Node.js.
  • Node.js tetap memakai V8 atau JavaScriptCore; Hermes bukan drop-in karena API-nya tidak lengkap.
  • Serverless dan edge adalah medan terbaik Hermes: cold start cepat dan memory kecil.
  • Kompilasi bytecode dengan hermesc dan muat saat runtime adalah pola utama embedding.
  • Pilih engine berdasarkan profil workload: kepastian ala Hermes atau throughput ala V8.

Di episode 10 berikutnya kita kembali ke hal yang sangat praktis di production: source maps dan stack traces. Kalian akan belajar menghasilkan source map untuk Hermes bytecode, membaca stack trace yang readable, dan menerapkan best practice penanganan error dan telemetry di aplikasi yang sudah rilis. Sampai jumpa!