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.wasmdenganContent-Type: application/octet-stream.WebAssembly.instantiateStreamingjalan 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
- Figma: engine-nya C++, pindah dari asm.js ke Wasm tahun 2017, dan waktu muat jadi lebih dari 3 kali lebih cepat.
- Google Earth: dari Native Client (khusus Chrome) ke Wasm, lalu jalan di Firefox, Edge, dan Opera sejak Februari 2020.
- AutoCAD Web: kode C++ berumur 35 tahun di-compile dengan Emscripten, rilis Maret 2018.
- Photoshop di web: Adobe memakai Emscripten dan Wasm (2021), tersedia untuk umum September 2023. Ditambah banyak game browser dari Unity dan Godot.
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 |
.wasmmengecil 50 sampai 78%, karena pola instruksinya berulang. Brotli 10 sampai 25% lebih kecil dari gzip.- Simpan versi terkompres saat build (
olahfoto.wasm.br), lalu kirim denganContent-Encoding: br,Content-Type: application/wasm, danVary: Accept-Encoding. Browser membuka kompresinya sebelum compile, jadiinstantiateStreamingtetap jalan. - Kompresi cuma mengecilkan unduhan. Browser tetap meng-compile 4.177 byte. Untuk mengecilkan modulnya sendiri: release, wasm-opt, strip (pelajaran Profiling).
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
- Vite 8.0.8 menaruh hash isi file di namanya:
olahfoto-Cp8ZQMRe.wasm. Kalau isinya berubah, namanya berubah. - Karena itu file ber-hash aman di-cache selamanya:
Cache-Control: public, max-age=31536000, immutable.index.htmlyang menunjuk ke nama baru diberiCache-Control: no-cache. - Vite meng-inline aset di bawah 4 KiB (
build.assetsInlineLimit, bawaannya 4096).olahfoto-dasar.wasm(3.302 byte, versi tanpa SIMD dari bagian berikutnya) ikut masuk ke JS sebagaidata:application/wasm;base64,...: sepertiga lebih besar dan gak punya cache sendiri. Denganbuild: { assetsInlineLimit: 0 }divite.config, dia jadi file sendiri:olahfoto-dasar-DEnIdDgB.wasm.
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
WebAssembly.validate(bytes)mengecek tanpa meng-compile. Engine tanpa SIMD menolak seluruh modul, bukan cuma fungsinya:olahfoto.wasmberisigrayscale_simd, danwasm-tools validate --features=-simd olahfoto.wasmmenjawabfunc 6 failed to validatekarenaSIMD support is not enabled. Versi dasarnya di-build tanpa fungsi itu: 3.302 byte.- Thread butuh
crossOriginIsolated(header COOP dan COEP). Tanpa itu, pakai versi satu thread. - Versi JavaScript tetap disimpan sebagai cadangan terakhir: lebih lambat, tapi tamu tetap bisa mengolah fotonya.
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;
}
}
- Setelah trap, isi memori instance itu bisa setengah jadi (misalnya allocator sedang di tengah pekerjaan). Instance baru lebih aman.
CompileError(file rusak, fitur gak didukung) danLinkError(import gak cocok) muncul saat memuat, bukan saat memanggil.
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),
}));
});
- Catat waktu muat, ukuran unduhan, versi modul, fitur yang terdeteksi, dan setiap
CompileError,LinkError, atauRuntimeErrorbeserta pesannya. sendBeacontetap terkirim walau tamu menutup halaman.
Checklist go-live tool foto Bu Sri
- Build release, wasm-opt, strip; ukuran dicatat (4.177 byte, 1.851 setelah brotli).
Content-Type: application/wasmdicek dengancurl -I, dan path.wasmyang salah membalas 404, bukanindex.html.- Brotli dan gzip aktif, dengan
Vary: Accept-Encoding. - Nama file ber-hash dengan
immutable;index.htmldenganno-cache. - CSP berisi
'wasm-unsafe-eval'. WebAssembly.validatememilih versi SIMD atau biasa; JS jadi cadangan terakhir.- Ukuran foto dicek sebelum masuk Wasm; trap ditangkap, instance diganti, dan dilaporkan.
- Monitoring mengirim waktu muat, versi, dan error; diuji di Chrome, Safari, Firefox, dan HP kelas bawah.
⚠️ Jebakan yang sering ketemu
- Router SPA membalas
.wasmdenganindex.html. Hasilnyaunsupported MIME type 'text/html'atauexpected magic word 00 61 73 6d, found 3c 21 64 6f. - CSP tanpa
'wasm-unsafe-eval'. Semua compile Wasm diblokir, padahal script-nya jalan. - Mengirim build SIMD tanpa cek. Engine tanpa SIMD menolak seluruh modul.
immutabledi nama file tanpa hash. Tamu terjebak di versi lama sampai cache-nya kedaluwarsa setahun lagi.- Memakai instance lagi setelah trap. Memorinya mungkin setengah jadi. Buat instance baru.
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.