Nim mengompilasi programnya menjadi JavaScript sebagaimana ia mengompilasi menjadi C. Hasilnya adalah satu berkas .js yang berjalan di node maupun browser tanpa runtime tambahan. Topik ini mengompilasi dan menjalankan program Nim dengan node, mengakses DOM melalui pustaka standar std/dom, menyajikan demo interaktif, lalu membungkus fungsi Nim menjadi modul yang dapat dimuat oleh ekosistem npm.
Kompilasi ke JavaScript#
nim js, atau --backend:js, menargetkan JavaScript alih-alih C. Tidak ada gcc dan tidak ada berkas C di nimcache, karena backend ini memancarkan JavaScript langsung. Pemetaan tipenya pun berbeda dari backend C, yaitu string Nim menjadi string JavaScript, int menjadi number, dan seq menjadi array, sehingga sebagian besar kode umum berjalan tanpa penyesuaian.
Program berikut adalah penghitung kata yang dipakai berulang pada topik ini.
# kata.nim — penghitung kata yang dikompilasi ke JavaScript
proc hitungKata(teks: string): int =
var dalamKata = false
for c in teks:
if c == ' ':
dalamKata = false
elif not dalamKata:
inc result
dalamKata = true
when isMainModule:
echo hitungKata("nim menghasilkan javascript yang rapi")
echo hitungKata(" spasi ganda dihitung benar ")# kompilasi ke JavaScript
nim js --hints:off kata.nim
# jalankan hasilnya dengan node
node kata.js5
4Berkas kata.js yang dihasilkan berdiri sendiri, yaitu runtime Nim untuk JavaScript tersertakan di dalamnya, sehingga cukup dipanggil dengan node tanpa berkas lain. Baris kedua keluaran membuktikan bahwa spasi ganda diperlakukan sebagai satu pemisah, karena setiap rentetan spasi hanya mengakhiri satu kata.
Rentang int pada batas JavaScript#
Pemetaan tipe di atas berdampak pada rentang int. Backend C mewarisi rentang bilangan bulat 64 bit dari mesin sasarannya, sedangkan backend JavaScript menjaga konsistensi semantik Nim dengan memeriksa rentang yang jauh lebih kecil, mengikuti batas bilangan bulat 32 bit bertanda. Penguraian teks menjadi angka dan penjumlahan biasa sama-sama diperiksa, sehingga pelanggaran rentang tidak lolos diam-diam, melainkan memunculkan error yang eksplisit. Program berikut memeriksa dua batas itu sekaligus, yaitu penguraian tepat di atas batas tertinggi dan penjumlahan yang melampauinya.
# ambang_int.nim — batas rentang int pada backend JavaScript
import std/strutils
try:
echo parseInt("2147483647")
echo parseInt("2147483648")
except ValueError as e:
echo "ditolak: ", e.msg
try:
echo 2147483647 + 1
except OverflowDefect as e:
echo "meluap: ", e.msg
echo 3.5 + 1.25# kompilasi program ambang rentang ke JavaScript
nim js --hints:off ambang_int.nim
# jalankan hasilnya dengan node
node ambang_int.js2147483647
ditolak: Parsed integer outside of valid range
meluap: over- or underflow
4.75Penguraian 2147483647 masih diterima, sedangkan 2147483648 langsung ditolak dengan ValueError, dan penjumlahan yang melewati batas yang sama memunculkan OverflowDefect. Program yang sama pada backend C menerima penguraian sepuluh digit tersebut dan mencetak 2147483648, sedangkan penjumlahannya berlanjut menjadi 2147483648, karena int di sana memang berukuran 64 bit. Kode yang bergantung pada rentang 64 bit karenanya perlu ditinjau sebelum disasar ke JavaScript, dan kebutuhan angka pecahan dengan rentang lebih luas dilayani tipe float yang memetakan langsung ke number, sebagaimana baris 4.75 pada keluaran di atas.
Mengakses DOM dengan std/dom#
Pustaka standar std/dom menyediakan binding bertipe untuk API DOM browser. Objek document dan window tersedia sebagai pengenal, kelas seperti Element dan Event memiliki tipe, dan akses atribut seperti innerHTML diperiksa kompilator. Kode berikut mengubah teks sebuah elemen ketika tombol ditekan, dan proc pasang dipanggil dari HTML melalui atribut onload.
# tidak-dijalankan
import std/dom
proc saatDiklik(ev: Event) {.exportc.} =
let pesan = document.getElementById("pesan")
pesan.innerHTML = "tombol ditekan dari Nim"
proc pasang() {.exportc.} =
let tombol = document.getElementById("tombol")
tombol.addEventListener("click", saatDiklik)<body onload="pasang()">
<button id="tombol" type="button">Tekan</button>
<p id="pesan">belum ada peristiwa</p>
<script src="dom.js"></script>
</body>Kompilasinya berjalan seperti biasa dengan nim js, tetapi eksekusinya menuntut browser karena di sanalah objek document hidup. Sandbox tidak memiliki browser, sehingga potongan di atas ditandai tidak dijalankan dan tidak diberi blok keluaran.
Demo interaktif#
Demo berikut mengulang logika hitungKata yang ditulis ulang dalam JavaScript murni agar dapat dicoba langsung di halaman. Ketik teks di dalam kotaknya, lalu amati jumlah kata dan karakter yang diperbarui pada setiap ketikan. Perilakunya sama dengan program kata.nim, termasuk cara spasi ganda diperlakukan sebagai satu pemisah.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Peraga penghitung kata</title>
<style>
body { font-family: sans-serif; margin: 12px; color: #1f2933; }
textarea { width: 100%; box-sizing: border-box; height: 72px; }
table { margin-top: 8px; }
th { text-align: left; }
td { font-weight: bold; padding-left: 16px; }
</style>
</head>
<body>
<p>Ketik teks, lalu amati hitungan di bawahnya.</p>
<textarea id="masukan">nim menghasilkan javascript yang rapi</textarea>
<table>
<tr><th>kata</th><td id="kata">5</td><th>karakter</th><td id="karakter">35</td></tr>
</table>
<script>
const masukan = document.getElementById('masukan');
function perbarui() {
const teks = masukan.value;
let kata = 0;
let dalamKata = false;
for (const c of teks) {
if (c === ' ') {
dalamKata = false;
} else if (!dalamKata) {
kata++;
dalamKata = true;
}
}
document.getElementById('kata').textContent = String(kata);
document.getElementById('karakter').textContent = String(teks.length);
}
masukan.addEventListener('input', perbarui);
perbarui();
</script>
</body>
</html>Integrasi dengan ekosistem npm#
Paket npm memuat modul JavaScript, dan modul CommonJS diekspor melalui module.exports. Proc Nim yang diberi pragma .exportc. mempertahankan namanya di JavaScript, sedangkan pragma .emit. menyisipkan kode JavaScript apa pun ke dalam berkas hasil kompilasi. Gabungan keduanya mengubah hasil nim js menjadi modul yang dapat dimuat dengan require.
# hitungjs.nim — modul Nim yang diekspor untuk ekosistem npm
proc hitungKata(teks: cstring): int {.exportc.} =
var dalamKata = false
for c in $teks:
if c == ' ':
dalamKata = false
elif not dalamKata:
inc result
dalamKata = true
{.emit: """
module.exports = { hitungKata: hitungKata };
""".}# kompilasi modul Nim menjadi JavaScript
nim js --hints:off hitungjs.nim
# muat hasil kompilasi sebagai modul CommonJS
node -e 'const m = require("./hitungjs.js"); console.log(m.hitungKata("empat kata di sini")); console.log(m.hitungKata(" dua kata "));'4
2Pengujian di atas memuat berkas hasil kompilasi langsung dengan require, sehingga tidak memerlukan jaringan maupun npm install. Parameter cstring dipilih agar teks tidak disalin menjadi string Nim pada setiap pemanggilan, dan tipe kembalian int otomatis menjadi number di sisi JavaScript. Untuk distribusi nyata, berkas ini ditempatkan di dalam paket bersama package.json, dan konsumen paket maupun bundler melihatnya sebagai modul CommonJS biasa.
Nama hasil exportc dapat disetel eksplisit bila nama Nim tidak cocok dengan konvensi penamaan JavaScript, misalnya .exportc: "hitungKataJS", dan pragma .emit. yang sama juga dapat memancarkan komentar maupun kode pembungkus lainnya. Berkas package.json pada paket yang nyata menunjuk hasil kompilasi melalui kunci main, sehingga require terhadap nama paket langsung menemukan modulnya tanpa menyebut nama berkas .js di sisi konsumen. Dengan susunan itu, logika yang ditulis dan diuji di Nim menjadi satu-satunya sumber kebenaran, sedangkan lapisan JavaScript hanya menjadi pintu masuk yang tipis.
Ringkasan#
nim jsmemancarkan satu berkas JavaScript mandiri yang berjalan di node maupun browser, dengan pemetaan tipestring,number, danarray.- Rentang
intpada backend JavaScript mengikuti batas 32 bit bertanda, denganOverflowDefectuntuk peluapan aritmetika danValueErroruntuk penguraian di luar rentang, berbeda dari backend C yang memakai 64 bit. - Pustaka
std/dommemberi akses DOM bertipe, dan kodenya hanya dapat dieksekusi di browser, bukan di node. .exportc.mempertahankan nama proc di JavaScript, dan.emit.menyisipkanmodule.exportssehingga hasil kompilasi menjadi modul CommonJS yang dapat dimuat denganrequire.
Referensi#
- Backends — Nim documentation — Penjelasan target JavaScript, termasuk akses DOM dan integrasinya dengan ekosistem web.
- Module std/dom — Nim documentation — Daftar binding DOM yang tersedia pada pustaka standar.
- Nim Compiler User Guide — Nim documentation
— Dokumentasi
--backend:jsdan opsi kompilasi terkait.