Wasm di Production — WebAssembly

WebAssembly di Production WebAssembly bukan teknologi eksperimental — perusahaan besar sudah memakainya di production untuk performa dan efisiensi yang tidak…

Wasm di production artinya mengirim file .wasm ke HP ribuan tamu dengan benar: cepat diunduh, mau di-compile browser, aman, punya cadangan kalau gagal, dan kamu tahu kalau ada yang rusak. Bayangin Bu Sri mengirim paket manisan carica ke pelanggan di seluruh Indonesia. Label isinya harus benar, kalau gak kurir menolak paketnya. Paketnya dikemas rapat supaya ongkirnya murah. Tiap versi kemasan diberi kode, jadi agen boleh menyimpan stok lama tanpa takut tertukar. Sebelum mengirim, Bu Sri mengecek apakah alamatnya bisa menerima paket berpendingin; kalau gak, dia kirim versi kering. Segel paket menjaga isinya, tapi apa yang dimasukkan ke paket tetap tanggung jawab Bu Sri. Dan nomor resinya dicatat. Label isi itu header Content-Type, kemasan rapat itu kompresi, kode versi itu nama file dengan hash, cek alamat itu feature detection, segel itu sandbox Wasm, isi paket itu import-mu, dan nomor resi itu monitoring.

🧪 Tebakan cepat: server Bu Sri mengirim olahfoto.wasm dengan Content-Type: application/octet-stream. WebAssembly.instantiateStreaming jalan normal, jalan tapi lebih lambat, atau gagal? Tebak dulu, jawabannya ada di bagian "Content-Type: application/wasm".

Siapa yang sudah memakai Wasm, dan kapan jangan

Polanya sama: kode C++ besar yang sudah ada, dan kerja CPU berat. Sebaliknya, jangan pakai Wasm untuk logika UI sederhana, manipulasi DOM, form CRUD, atau aplikasi yang lebih butuh kecepatan developer daripada kecepatan hitung. Di situ JavaScript sudah cukup cepat, dan Wasm cuma menambah toolchain, debugging yang lebih susah, dan ongkos menyeberang.

Content-Type: application/wasm

instantiateStreaming meng-compile sambil mengunduh, tapi cuma kalau server bilang file-nya application/wasm. Kalau gak, dia menolak. Ini pesan aslinya:

Browser Content-Type: application/octet-stream
Chromium 147 TypeError: Failed to execute 'compile' on 'WebAssembly': Incorrect response MIME type. Expected 'application/wasm'.
WebKit 26.4 TypeError: Unexpected response MIME type. Expected 'application/wasm'
Firefox 146 TypeError: WebAssembly: Response has unsupported MIME type 'application/octet-stream' expected 'application/wasm'

Jadi jawaban tebakannya: gagal, di ketiga browser. Kasus yang sering ketemu: router SPA membalas path .wasm yang salah dengan index.html. Firefox menulis unsupported MIME type 'text/html', dan kalau kodenya memakai arrayBuffer() lalu instantiate, pesannya CompileError: WebAssembly.compile(): expected magic word 00 61 73 6d, found 3c 21 64 6f @+0: byte 3c 21 64 6f itu <!do dari <!doctype html>. Cek dengan curl -I bahwa responsnya 200 dan content-type: application/wasm.

Kompresi: gzip dan brotli

Diukur dengan gzip level 9 dan brotli quality 11:

File Ukuran gzip brotli
olahfoto.wasm 4.177 byte 2.058 1.851
olahfoto-simd.wasm 6.040 byte 2.924 2.529
homestay_kabut_bg.wasm (wasm-pack) 14.896 byte 6.764 5.797
foto-abu.wasm (WASI) 63.172 byte 25.721 21.674
foto-abu dari Go 2.677.059 byte 770.794 578.596

Cache: nama file dengan hash

import olahfotoUrl from './olahfoto.wasm?url'; // Vite memberi URL file yang sudah di-hash

WebAssembly.instantiateStreaming(fetch(olahfotoUrl)).then(({ instance }) => {
  // instance.exports.grayscale, blur_h, ...
});
$ vite build
dist/index.html                     0.25 kB │ gzip: 0.20 kB
dist/assets/olahfoto-Cp8ZQMRe.wasm  4.17 kB │ gzip: 2.05 kB
dist/assets/index-CW3UgSLM.js       0.83 kB │ gzip: 0.48 kB

Cek fitur, siapkan cadangan

// (module (func (result v128) i32.const 0 i8x16.splat i8x16.popcnt)), 31 byte dari wat2wasm
const UJI_SIMD = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11]);

function pilihVersi() {
  if (typeof WebAssembly !== 'object') return 'js';             // tanpa Wasm: grayscaleJs
  if (WebAssembly.validate(UJI_SIMD)) return 'olahfoto.wasm';  // berisi grayscale_simd
  return 'olahfoto-dasar.wasm';                                  // tanpa satu pun instruksi SIMD
}
const bisaThread = typeof crossOriginIsolated !== 'undefined' && crossOriginIsolated; // pelajaran Threading

Keamanan: sandbox, import, dan CSP

Modul Wasm cuma bisa menyentuh linear memory-nya sendiri dan fungsi yang kamu import. Gak ada akses DOM, jaringan, atau file kecuali lewat import itu. Jadi import-mu adalah pintunya: jangan meng-import fungsi yang menjalankan teks sebagai kode atau mengambil URL apa pun yang diberikan modul. Kode C atau C++ di dalam Wasm juga masih bisa menimpa datanya sendiri (buffer overflow tetap terjadi di dalam linear memory); pemeriksaan batas cuma ada di ujung memorinya. Cek ukuran input sebelum memanggil Wasm.

Content-Security-Policy script-src 'self' memblokir compile Wasm di ketiga browser:

Browser Pesan
Chromium 147 CompileError: WebAssembly.instantiate(): Compiling or instantiating WebAssembly module violates the following Content Security policy directive because 'unsafe-eval' is not an allowed source of script ...
WebKit 26.4 CompileError: Refused to create a WebAssembly object because 'unsafe-eval' or 'wasm-unsafe-eval' is not an allowed source of script ...
Firefox 146 CompileError: call to WebAssembly.instantiate() blocked by CSP

Tambahkan 'wasm-unsafe-eval': script-src 'self' 'wasm-unsafe-eval'. Itu mengizinkan Wasm tanpa mengizinkan eval. Didukung sejak Chrome 97, Firefox 102, dan Safari 16. 'unsafe-eval' juga membuka Wasm, tapi sekaligus membuka eval.

Trap dan error handling

Trap adalah error yang menghentikan fungsi Wasm di tengah jalan. Pesannya beda per browser:

Trap Chromium 147 WebKit 26.4 Firefox 146
Baca di luar memori RuntimeError: memory access out of bounds RuntimeError: Out of bounds memory access RuntimeError: index out of bounds
unreachable RuntimeError: unreachable RuntimeError: Unreachable code should not be executed RuntimeError: unreachable executed

Panic Rust dengan panic = "abort" berakhir sebagai unreachable. Contohnya resize_area dengan lebar sumber 0: Rust membagi dengan 0, panic, dan JS cuma melihat RuntimeError: unreachable, tanpa pesan panic-nya.

function grayscaleAman(foto) {
  try {
    return grayscaleWasm(foto);
  } catch (e) {
    if (e instanceof WebAssembly.RuntimeError) {
      laporkan('trap', e);
      olahfoto = null; // jangan pakai instance yang sama lagi; buat baru di panggilan berikutnya
      return grayscaleJs(foto); // cadangan
    }
    throw e;
  }
}

Monitoring

const mulai = performance.now();
WebAssembly.instantiateStreaming(fetch(olahfotoUrl)).then(({ instance }) => {
  const unduhan = performance.getEntriesByName(new URL(olahfotoUrl, location.href).href)[0];
  navigator.sendBeacon('/api/metrik', JSON.stringify({
    modul: olahfotoUrl,                         // nama ber-hash = versi
    muatMs: Math.round(performance.now() - mulai),
    transferSize: unduhan?.transferSize,        // 0 kalau dari cache
    encodedBodySize: unduhan?.encodedBodySize,  // ukuran terkompres
    decodedBodySize: unduhan?.decodedBodySize,  // 4177
    simd: WebAssembly.validate(UJI_SIMD),
  }));
});

Checklist go-live tool foto Bu Sri

⚠️ Jebakan yang sering ketemu

TL;DR: Wasm sudah menjalankan Figma, Google Earth, AutoCAD Web, Photoshop di web, dan banyak game browser; jangan pakai untuk UI sederhana, DOM, atau aplikasi yang lebih butuh kenyamanan developer. Untuk mengirimnya: Content-Type: application/wasm (tanpa itu instantiateStreaming gagal di Chromium, WebKit, dan Firefox), kompresi brotli atau gzip (4.177 jadi 1.851 atau 2.058 byte), nama file ber-hash (olahfoto-Cp8ZQMRe.wasm) dengan Cache-Control: immutable, dan awas Vite meng-inline aset di bawah 4 KiB. Pilih versi dengan WebAssembly.validate (SIMD) dan crossOriginIsolated (thread), simpan JS sebagai cadangan. Wasm ter-sandbox, tapi import-mu adalah pintunya; CSP butuh 'wasm-unsafe-eval' (Chrome 97, Firefox 102, Safari 16). Tangkap RuntimeError (out of bounds, unreachable dari panic Rust), ganti instance-nya, pakai cadangan, dan laporkan. Monitoring mencatat waktu muat, ukuran, versi, fitur, dan error lewat sendBeacon.

Yang akan kamu pelajari