Advanced (Diperbarui: 2/6/2026)

Integrasi WebAssembly dengan Claude Code: Rust, wasm-pack, dan Vite

Panduan integrasi Rust WebAssembly ke Vite dengan Claude Code, wrapper bertipe, benchmark, use case, dan pitfall umum.

Integrasi WebAssembly dengan Claude Code: Rust, wasm-pack, dan Vite

Peran Claude Code dalam integrasi WebAssembly

WebAssembly, sering disingkat Wasm, adalah format biner portabel yang memungkinkan kode Rust, C, C++, dan bahasa lain berjalan di browser atau Node.js. Wasm bukan pengganti penuh JavaScript. Dalam proyek nyata, Wasm paling berguna sebagai akselerator untuk bagian kecil yang berat: pemrosesan gambar, kompresi, manipulasi byte untuk kriptografi, kalkulasi numerik, agregasi CSV, atau penggunaan ulang library Rust/C++ yang sudah ada.

Claude Code membantu karena integrasi Wasm yang baik tidak selesai di satu file. Kita perlu fungsi Rust, build dengan wasm-pack, glue code dari wasm-bindgen, loading async di Vite, wrapper TypeScript, benchmark, dan review prompt yang memeriksa biaya batas JS-Wasm. Batas JS-Wasm adalah titik saat data berpindah dari JavaScript ke WebAssembly atau sebaliknya. Jika batas ini dilintasi terlalu sering dengan panggilan kecil, hasilnya bisa lebih lambat daripada JavaScript biasa.

Artikel ini membuat contoh kecil yang bisa dicopy: membalik warna buffer RGBA, menjumlahkan kolom numerik dari CSV, dan menghitung checksum ringan pada bytes. Tiga contoh ini mewakili data gambar, teks, dan biner. Pola yang sama bisa diperluas untuk pemrosesan cepat di browser, porting aset Rust/C++, kompresi, codec khusus, atau kalkulasi lokal ketika data tidak boleh dikirim ke server. Untuk gambaran performa yang lebih luas, baca juga Claude Code performance optimization.

Gunakan referensi resmi saat bekerja: MDN WebAssembly untuk platform, wasm-bindgen Guide untuk jembatan Rust-JavaScript, dan wasm-pack repository untuk alur build. Minta Claude Code mengikuti batas ini sebelum membuat loader khusus.

Tentukan use case sebelum menulis kode

Wasm tidak otomatis lebih cepat. Wasm bagus ketika menerima blok data besar, memprosesnya dalam loop rapat, lalu mengembalikan hasil. Wasm kurang cocok jika JavaScript memanggil fungsi kecil ribuan kali. Jadi prompt pertama sebaiknya bukan “ubah ke Wasm”, tetapi “operasi mana yang pantas melewati batas JS-Wasm dan bagaimana cara mengukurnya”.

Use caseMengapa cocok untuk WasmYang perlu dicek Claude Code
Pemrosesan gambarBuffer RGBA cocok untuk loop linearJumlah copy, baca/tulis Canvas, benchmark adil
Kriptografi, kompresi, codecBanyak bekerja dengan byte array dan library RustApakah perlu library audited dan bagian mana yang tidak boleh custom
CSV dan kalkulasi numerikParsing dan agregasi mengulang banyak operasiBaris kosong, NaN, file besar, strategi error
Porting Rust atau C++Logika yang sudah teruji bisa dipakai di browserOS API, file I/O, thread, dependency yang tidak kompatibel
Pemrosesan berat di browserData sensitif tetap di perangkat penggunaUkuran load awal, fallback, target browser

Dalam eksperimen Masa, pendekatan paling aman adalah memindahkan satu fungsi dulu lalu mengukur. Pada gambar, fungsi Rust cepat, tetapi waktu membaca dan menulis ImageData bisa mendominasi. Pada CSV, mengirim seluruh teks sekali lebih stabil daripada memanggil Wasm per baris. Constraint seperti ini harus masuk ke prompt Claude Code.

Modul Rust minimal dengan wasm-pack

wasm-pack membangun crate Rust, menjalankan wasm-bindgen, lalu menghasilkan folder pkg berisi binary Wasm, loader JavaScript, metadata package, dan deklarasi TypeScript. wasm-bindgen adalah library yang mengekspos fungsi Rust tertentu agar bisa dipanggil dari JavaScript.

# Cargo.toml
[package]
name = "wasm-lab"
version = "0.1.0"
edition = "2021"

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

[dependencies]
wasm-bindgen = "0.2"
// src/lib.rs
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn invert_rgba(pixels: &mut [u8]) {
    for chunk in pixels.chunks_exact_mut(4) {
        chunk[0] = 255 - chunk[0];
        chunk[1] = 255 - chunk[1];
        chunk[2] = 255 - chunk[2];
    }
}

#[wasm_bindgen]
pub fn sum_csv_column(csv: &str, column: usize) -> f64 {
    csv.lines()
        .filter(|line| !line.trim().is_empty())
        .filter_map(|line| line.split(',').nth(column))
        .filter_map(|cell| cell.trim().parse::<f64>().ok())
        .sum()
}

#[wasm_bindgen]
pub fn fnv1a32(bytes: &[u8]) -> u32 {
    let mut hash = 0x811c9dc5u32;

    for byte in bytes {
        hash ^= u32::from(*byte);
        hash = hash.wrapping_mul(0x01000193);
    }

    hash
}
rustup target add wasm32-unknown-unknown
cargo install wasm-pack
wasm-pack build --target web --out-dir pkg

Fungsi fnv1a32 bukan hash kriptografi yang aman. Untuk password, signature, pembayaran, atau token, gunakan Web Crypto API atau library yang sudah diaudit. Di sini fungsinya hanya untuk contoh data biner yang kecil.

Loading di Vite dengan wrapper bertipe

Setelah build, akan ada pkg/wasm_lab.js dan pkg/wasm_lab.d.ts. Di Vite, import modul yang dihasilkan, tunggu init(), lalu expose API kecil lewat TypeScript wrapper. Dengan begitu UI tidak memanggil Wasm sebelum siap dan tidak menginisialisasi ulang pada setiap klik.

// src/wasm-client.ts
import init, {
  fnv1a32,
  invert_rgba,
  sum_csv_column,
} from "../pkg/wasm_lab";

export type WasmClient = {
  invertImage(imageData: ImageData): Promise<ImageData>;
  sumCsvColumn(csv: string, columnIndex: number): Promise<number>;
  checksum(bytes: Uint8Array): Promise<number>;
};

let initPromise: Promise<void> | undefined;

async function ensureWasm(): Promise<void> {
  initPromise ??= init().then(() => undefined);
  return initPromise;
}

export const wasmClient: WasmClient = {
  async invertImage(imageData) {
    await ensureWasm();

    const pixels = new Uint8Array(
      imageData.data.buffer,
      imageData.data.byteOffset,
      imageData.data.byteLength,
    );

    invert_rgba(pixels);
    return imageData;
  },

  async sumCsvColumn(csv, columnIndex) {
    await ensureWasm();
    return sum_csv_column(csv, columnIndex);
  },

  async checksum(bytes) {
    await ensureWasm();
    return fnv1a32(bytes);
  },
};
// src/main.ts
import { wasmClient } from "./wasm-client";

const fileInput = document.querySelector<HTMLInputElement>("#csv-file");
const output = document.querySelector<HTMLPreElement>("#output");

fileInput?.addEventListener("change", async () => {
  const file = fileInput.files?.[0];
  if (!file || !output) return;

  const csv = await file.text();
  const total = await wasmClient.sumCsvColumn(csv, 2);
  output.textContent = `column 2 total: ${total.toFixed(2)}`;
});

Untuk alur wasm-pack --target web, mulai dari konfigurasi Vite standar. Plugin baru diperlukan jika kamu mengimpor .wasm mentah atau memakai pola bundling lain. Bug awal biasanya berasal dari path yang salah atau init() yang belum ditunggu.

Prompt review untuk Claude Code

Claude Code sebaiknya diminta mengimplementasikan lalu melakukan review kritis. Prompt review harus fokus pada async init, copy memori, batas JS-Wasm, DOM, tipe, dan perintah verifikasi.

Review only these files:
- src/lib.rs
- pkg/wasm_lab.d.ts
- src/wasm-client.ts
- src/main.ts
- src/bench.ts

Goal:
Integrate the Rust WebAssembly module into the Vite app without changing UI behavior.

Check:
1. init() is awaited before any exported Wasm function is called.
2. init() is cached and not repeated for every click or file upload.
3. Large arrays cross the JS-Wasm boundary at most once per user action.
4. DOM updates stay in TypeScript, not inside Rust.
5. The wrapper exposes typed methods and keeps generated pkg files out of hand edits.
6. Benchmarks compare the same input data for JavaScript and Wasm.

Run:
wasm-pack build --target web --out-dir pkg
npm run typecheck
npm run build

Untuk tim, simpan aturan ini di CLAUDE.md. Setiap perubahan Wasm akan melewati review yang sama, bukan bergantung pada ingatan satu orang.

Benchmark dan langkah verifikasi

Jangan menyetujui migrasi Wasm hanya karena terasa cepat. Ukur input yang sama dan output yang sama. Benchmark berikut membandingkan inversi RGBA di JavaScript dan Wasm.

// src/bench.ts
import { wasmClient } from "./wasm-client";

function invertJs(pixels: Uint8Array): void {
  for (let index = 0; index < pixels.length; index += 4) {
    pixels[index] = 255 - pixels[index];
    pixels[index + 1] = 255 - pixels[index + 1];
    pixels[index + 2] = 255 - pixels[index + 2];
  }
}

function cloneImageData(source: Uint8Array, width: number, height: number): ImageData {
  return new ImageData(new Uint8ClampedArray(source), width, height);
}

export async function runBench(): Promise<void> {
  const width = 1920;
  const height = 1080;
  const source = new Uint8Array(width * height * 4);
  crypto.getRandomValues(source);

  const jsPixels = new Uint8Array(source);
  const wasmImage = cloneImageData(source, width, height);

  const jsStart = performance.now();
  invertJs(jsPixels);
  const jsMs = performance.now() - jsStart;

  const wasmStart = performance.now();
  await wasmClient.invertImage(wasmImage);
  const wasmMs = performance.now() - wasmStart;

  console.table({
    javascriptMs: Number(jsMs.toFixed(2)),
    wasmMs: Number(wasmMs.toFixed(2)),
    ratio: Number((jsMs / wasmMs).toFixed(2)),
  });
}
wasm-pack build --target web --out-dir pkg
npm run typecheck
npm run build
npm run dev

Jika hasil Wasm mengecewakan, cek konversi data lebih dulu. Canvas, ImageData, string, dan build development bisa menyembunyikan biaya sebenarnya. Kirim output benchmark ke Claude Code dan minta rekomendasi: tetap memakai Wasm, pindah ke Web Worker, atau cukup optimasi JavaScript.

Pitfall yang sering muncul

Pitfall pertama adalah inisialisasi async. init() harus selesai sebelum fungsi export dipanggil. Cache promise ini di wrapper.

Pitfall kedua adalah ukuran bundle. Setiap crate Rust bisa memperbesar .wasm. Mulai dari satu fungsi dan cek production build.

Pitfall ketiga adalah biaya batas JS-Wasm. Jangan memanggil fungsi kecil di dalam loop. Kirim array, string, atau buffer besar sekali jalan.

Pitfall keempat adalah mencoba mengontrol DOM dari Wasm. Event, render, accessibility, dan error message sebaiknya tetap di TypeScript.

Pitfall kelima adalah copy memori yang tidak terlihat. Typed array, string, dan ImageData bisa disalin oleh binding. Benchmark harus memasukkan biaya konversi ini.

Pitfall keenam adalah kompatibilitas browser dan security header. Wasm dasar sudah luas dukungannya, tetapi Wasm threads dan SharedArrayBuffer butuh COOP dan COEP. Situs dengan iklan, iframe, atau CDN perlu menguji hal ini lebih awal.

Workflow tim dan CTA

Untuk eksperimen pribadi, kode ini cukup. Untuk tim, tentukan logika mana yang pindah ke Rust, apa yang tetap di TypeScript, bagaimana memperlakukan file generated di pkg, browser apa yang didukung, dan benchmark mana yang memblokir merge. Aturan ini sebaiknya masuk ke CLAUDE.md dan prompt review.

ClaudeCodeLab dapat membantu menerapkan alur ini ke repository nyata: memilih use case Wasm yang tepat, mereview aset Rust/C++, mendesain benchmark, dan melatih tim memakai Claude Code dengan aman. Jika WebAssembly memengaruhi performa produksi, pemrosesan data sensitif di browser, atau arsitektur frontend bersama, mulai dari Claude Code training and consultation.

Catatan verifikasi

Saat mencoba alur ini, masalah awal bukan pada fungsi Rust, tetapi pada kapan init() dipanggil. Setelah inisialisasi disimpan di wasm-client.ts, image processing, CSV aggregation, dan checksum berjalan lewat jalur yang sama. Input kecil cukup cepat di JavaScript; buffer Full HD dan CSV besar lebih jelas menunjukkan trade-off. Ukur seluruh batas JS-Wasm, bukan hanya isi fungsi.

#Claude Code #WebAssembly #Wasm #Rust #performance
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.