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.

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.
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):
#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.
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)?
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:
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.
Untuk memanfaatkan Hermes di server, workflow khasnya adalah: kompilasi JavaScript menjadi bytecode saat build, lalu muat bytecode itu saat runtime. Kompilasi dilakukan dengan hermesc:
hermesc -emit-binary -O -out worker.hbc worker.jsHasilnya 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.
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:
#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.
Strategi optimasi yang benar bergantung di mana engine berjalan. Inilah perbandingan yang perlu diingat:
| Aspek | Mobile (React Native) | Server / Edge |
|---|---|---|
| Prioritas utama | Startup cepat dan memori rendah | Cold start dan latensi invoke |
| Bentuk kode | Bytecode HBC dari bundle | Bytecode HBC atau snapshot |
| Profil beban | Intermiten, dipakai-user | On-demand, banyak instance |
| Concurrency | Satu UI thread + workers | Banyak instance paralel |
| Kekuatan Hermes | Footprint kecil, parse nol | AOT, loading instan |
| Kelemahan | Tanpa JIT, peak CPU terbatas | Tanpa 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.
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:
hermesc dan muat saat runtime adalah pola utama embedding.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!