看了 wasm-pack build --target web 產生的 pkg/ 目錄,搞懂了 JS 膠水程式碼的角色。

wasm-pack 輸出四個檔案:

檔案 用途
.wasm 編譯後的 WASM 二進位
.js JS 膠水程式碼(runtime 必須
.d.ts TypeScript 型別宣告(純靜態,runtime 不用
_bg.wasm.d.ts 原始 WASM exports 的型別宣告

.d.ts 不參與執行——它們只給 TypeScript 編譯器做型別檢查用。整個流程不涉及 TypeScript 編譯。

膠水程式碼做兩件事:

1. 載入 WASMinit()WebAssembly.instantiateStreaming 串流編譯 .wasm 檔,邊下載邊編譯。

2. 雙向橋接 WASM 和瀏覽器 API

  • JS → WASM:處理型別轉換。WASM 只懂數字,所以字串要先編碼成 UTF-8 寫進 WASM 線性記憶體,再傳指標和長度:

    export function start(canvas_id, grid_width, grid_height) {
        const ptr0 = passStringToWasm0(canvas_id, wasm.__wbindgen_malloc, ...);
        const len0 = WASM_VECTOR_LEN;
        return wasm.start(ptr0, len0, grid_width, grid_height);
    }
  • WASM → JSweb_sys 的每個呼叫都對應一個 JS import 函式。以 WebGPU 的 device.createBuffer() 為例,Rust 端呼叫 web_sys → WASM 呼叫 import → JS 膠水程式碼呼叫真正的瀏覽器 API:

    __wbg_createBuffer_fb1752eab5cb2a7f: function(arg0, arg1) {
        const ret = arg0.createBuffer(arg1);
        return ret;
    }

在 wgpu Game of Life 專案裡,膠水程式碼包含大約 200 個這樣的橋接函式,全部由 wasm-bindgen 在建置時根據 #[wasm_bindgen]web_sys 的使用自動生成。