Wasm dari Rust (wasm-pack) — WebAssembly

Rust → WebAssembly Rust adalah bahasa paling populer untuk WebAssembly. Toolchain-nya mature, hasilnya compact, dan integrasi dengan JavaScript sangat baik…

wasm-pack adalah tool yang mengubah kode Rust jadi paket siap pakai untuk JavaScript: dia meng-compile Rust ke .wasm, menjalankan wasm-bindgen untuk membuat kode JavaScript perantaranya (glue code) dan file tipe TypeScript, mengecilkan .wasm dengan wasm-opt, lalu menulis package.json. Bayangin carica, oleh-oleh khas Dieng. Buahnya dimasak jadi manisan, dimasukkan ke botol dengan label dan cara penyajian, ditutup rapat, lalu dikemas dalam kardus berlabel toko supaya siap dipajang. Buahnya itu kode Rust, botol dan labelnya glue code JavaScript, tutup rapatnya wasm-opt, kardusnya package.json. wasm-pack adalah pabrik yang mengerjakan semuanya dengan satu perintah.

🧪 Tebakan cepat: fungsi hargaInap yang di WAT cuma 47 byte ditulis ulang dalam Rust lalu di-build dengan wasm-pack build. File .wasm-nya kira-kira berapa besar: 47 byte, 14 KB, atau 2 MB? Tebak dulu, jawabannya ada di bagian "Ukuran file".

Siapkan toolchain

Kamu butuh Rust (lewat rustup), target wasm32-unknown-unknown, dan wasm-pack:

rustup target add wasm32-unknown-unknown
curl https://wasm-bindgen.github.io/wasm-pack/installer/init.sh -sSf | sh
wasm-pack --version
# wasm-pack 0.15.0

Proyeknya: homestay-kabut

Buat proyeknya dengan cargo new --lib homestay-kabut, lalu ubah Cargo.toml jadi begini:

[package]
name = "homestay-kabut"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

Lalu src/lib.rs berisi dua fungsi sepanjang jalur ini, harga menginap dan grayscale foto kamar:

use wasm_bindgen::prelude::*;

/// Harga menginap di Homestay Kabut: malam × harga per malam (rupiah).
#[wasm_bindgen(js_name = hargaInap)]
pub fn harga_inap(malam: i32, harga_per_malam: i32) -> i32 {
    malam * harga_per_malam
}

/// Foto kamar jadi abu-abu, langsung di array-nya (RGBA, 4 byte per piksel).
#[wasm_bindgen]
pub fn grayscale(piksel: &mut [u8]) {
    for px in piksel.chunks_exact_mut(4) {
        let abu = ((px[0] as u32 * 77 + px[1] as u32 * 150 + px[2] as u32 * 29) >> 8) as u8;
        px[0] = abu;
        px[1] = abu;
        px[2] = abu;
    }
}

Build dengan wasm-pack

$ wasm-pack build --target web
[INFO]: 🎯  Checking for the Wasm target...
[INFO]: 🌀  Compiling to Wasm...
   Compiling homestay-kabut v0.1.0 (/Users/sri/homestay-kabut)
    Finished `release` profile [optimized] target(s) in 0.48s
[INFO]: ⬇️  Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ✨   Done in 0.98s
[INFO]: 📦   Your wasm pkg is ready to publish at /Users/sri/homestay-kabut/pkg.

(Path folder di laptopmu tentu beda.) Hasilnya ada di folder pkg/:

File Ukuran Isinya
homestay_kabut_bg.wasm 14.896 byte kode Rust yang sudah jadi Wasm
homestay_kabut.js 5.311 byte glue code: fungsi JS yang memanggil Wasm, dan init()
homestay_kabut.d.ts 1.649 byte tipe TypeScript untuk hargaInap dan grayscale
package.json 280 byte supaya folder ini bisa jadi paket npm

Ini potongan glue code yang dibuat wasm-bindgen:

export function hargaInap(malam, harga_per_malam) {
    const ret = wasm.hargaInap(malam, harga_per_malam);
    return ret;
}

export function grayscale(piksel) {
    var ptr0 = passArray8ToWasm0(piksel, wasm.__wbindgen_malloc);
    var len0 = WASM_VECTOR_LEN;
    wasm.grayscale(ptr0, len0, piksel);
}

Selain build, wasm-pack juga punya wasm-pack test (menjalankan test di Node atau di browser headless), wasm-pack pack (membuat file .tgz paketnya), dan wasm-pack publish (mengunggahnya ke npm).

Pakai di browser

<script type="module">
  import init, { hargaInap, grayscale } from './pkg/homestay_kabut.js';

  await init(); // unduh dan instantiate homestay_kabut_bg.wasm
  console.log(hargaInap(2, 350000)); // 700000

  const px = new Uint8Array([200, 120, 40, 255]);
  grayscale(px);
  console.log(px); // Uint8Array(4) [135, 135, 135, 255]
</script>

target web, bundler, nodejs

File .wasm-nya sama persis di ketiga target (14.896 byte). Yang beda cuma glue code-nya:

Target Cara memuat .wasm Cara memakainya
web init() mengambilnya dengan fetch import init, { hargaInap } from './pkg/homestay_kabut.js', lalu await init()
bundler (default kalau --target gak ditulis) import * as wasm from "./homestay_kabut_bg.wasm", diurus bundler import { hargaInap } from 'homestay-kabut'
nodejs require('fs').readFileSync lalu new WebAssembly.Module (CommonJS) const { hargaInap } = require('./pkg/homestay_kabut.js')

Target bundler butuh bundler yang bisa meng-import .wasm langsung, seperti webpack 5 dengan experiments.asyncWebAssembly. Di Vite, pakai plugin seperti vite-plugin-wasm, atau pakai target web.

Ukuran file

Build Ukuran .wasm
harga.wat lewat wat2wasm 47 byte
Rust tanpa wasm-bindgen (#[unsafe(no_mangle)] pub extern "C" fn), cargo build --release 338 byte, 68 byte setelah wasm-strip
wasm-pack --release, hargaInap saja 13.588 byte
wasm-pack --release, hargaInap + grayscale 14.896 byte (6.762 byte setelah gzip)
wasm-pack --dev, hargaInap + grayscale 64.731 byte

Jadi jawaban tebakannya: sekitar 14 KB. Perkaliannya sendiri tetap beberapa byte. Sisanya adalah perlengkapan wasm-bindgen yang selalu ikut: allocator memori (dlmalloc), tabel untuk menyimpan objek JS, dan penanganan panic. Ongkos itu dibayar sekali; menambah grayscale cuma menambah 1,3 KB. --dev lebih besar karena berisi info debug dan gak dikecilkan wasm-opt.

Ini juga alasan Rust populer untuk Wasm: Rust gak butuh garbage collector, jadi gak ada runtime GC yang ikut dikirim, binary-nya kecil, dan tool-nya (wasm-pack, wasm-bindgen, web-sys) matang.

📌 Status wasm-pack dan wasm-bindgen sejak 2025

⚠️ Jebakan yang sering ketemu

TL;DR: wasm-pack mengubah crate Rust jadi paket untuk JavaScript: cargo build ke wasm32-unknown-unknown, wasm-bindgen membuat glue code JS dan .d.ts, wasm-opt mengecilkan .wasm, dan package.json ditulis. Syaratnya crate-type = ["cdylib"] dan dependency wasm-bindgen; fungsi yang di-export diberi #[wasm_bindgen] (js_name untuk mengganti namanya). wasm-pack build --target web dipakai dengan import init, { hargaInap } from './pkg/homestay_kabut.js' dan await init(); target bundler (default) untuk bundler, nodejs untuk require di Node. &mut [u8] disalin masuk dan keluar otomatis. Ukurannya: hargaInap + grayscale 14.896 byte di --release, 64.731 byte di --dev, sebagian besar perlengkapan wasm-bindgen. wasm-pack juga punya test, pack, dan publish. Sejak 2025 organisasi rustwasm diarsipkan; wasm-bindgen dan sekarang wasm-pack dirawat di organisasi wasm-bindgen.

Yang akan kamu pelajari