RustのWasm周りのクレートまとめと、Trunkを使ってRustで書いたWasmをブラウザ上で簡単に実行する
はじめに
この記事ではRustのWasmを使う際に便利なライブラリたちをまとめて、その後Trunkというツールを利用してRustでWasmを書いて実行するところまでを試してみます。
記事執筆時のRustのバージョンは1.61.0です。
RustでのWasmの実行周りのエコシステムまとめ
RustはWasmをコンパイルのターゲットとして公式でサポートしています。
wasm32-unknown-unknownというターゲットをrustupで追加することでWasm向けにRustをコンパイルできます。
ただしこれ単体で使うより、さらに周辺ライブラリを組み合わせて使うことが多いようです。
Rustでは周辺のライブラリなどを使うことでより便利にWasmを利用できます。
以下にRustでWasmを使う場合にお世話になるであろう周辺ライブラリなどを紹介します。
また、今回紹介しきれない範囲などについて、wasm-bindgenのガイドにとても詳しくRustでWasmを触るための何もかもが書かれているのでそちらも適宜読むと良いでしょう。
wasm-bindgen
wasm-bindgenはWasmとJavaScriptの間の糊付けを担当します。
例えば次のように#[wasm_bindgen]をつけて関数を宣言することで、Rustで書いたWasmの中からJavaScriptの関数を利用したり、逆にRustで書いたWasmの関数をJavaScriptから呼べるようになります。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}
import { greet } from "./hello_world";
greet("World!");
現在、Wasmは実行する際にはJavaScriptの内部から呼び出す必要があり、JavaScriptとの糊付けのコードはだいたい必須となるため、wasm-bindgenは多くの場合必須となるでしょう。
wasm-bindgenはJsValueというJavaScriptのオブジェクトをRustで表現した型を持っています。
このJsValueをブラウザAPIの型として扱う場合、例えばNumber型であったりArray型のようなJavaScript固有の型、あるいはHtmlInputElementなどのようなブラウザのオブジェクト固有の型については、後述のjs_sys及びweb_sysクレートを使います。
wasm-bindgenのserde-serializeというfeatureを有効にすることで、JsValueとJSONへシリアライズ/デシリアライズできる値との変換ができるようになります。
これによってJavaScriptから渡されるObjectをserdeでRustに取り込むことなどが可能になります。
場合によってはこの機能は後述のserde-wasm-bindgenを利用したほうが効率が良いかもしれません。
wasm-bindgen-cli
wasm-bindgen-cli0は、前述のwasm-bindgenをつけてビルドしたRustの生成するWasmを食わせて新たに使いやすいWasmやJavaScriptコードなどを生成するツールです。
wasm-bindgen-cliを利用すると、Wasmファイルの他に糊付けのためのJavaScriptコードも吐き出してくれるので、JavaScriptからまるでWasmの関数を直接呼び出したりするように使うことができます。
糊付けのコードの種類に応じて次のtargetを--target [target name]として指定できます。
- bundler: Webpackなどでバンドルするためのライブラリとしての糊付けコード
- web: ブラウザから読み込まれるモジュールとして使う糊付けコード
- nodejs: Node.jsのrequireで読み込める形式としての糊付けコード
- deno: Denoからインポートできるモジュール用の糊付けコード
- no-modules: ブラウザから読み込まれるモジュールだが、Webと違いES Moduleに対応していない環境に向けた糊付けのコード
targetについては詳しくはドキュメントのページを読むと良いでしょう。
例えば上記のmain.rsを--target webで呼び出す場合、次のようなwasm_bindgen_test.jsとwasm_bindgen_test_bg.wasmというバイナリが生成されています。
(ついでにwasm_bindgen_test_bg.wasm.d.tsとwasm_bindgen_test.d.tsというTypeScriptの型定義ファイルも生成されますが、これはオプションで無効化もできます)
wasm_bindgen_test.js
let wasm;
const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
    if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
        cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
    }
    return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
    return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
let WASM_VECTOR_LEN = 0;
const cachedTextEncoder = new TextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
    ? function (arg, view) {
    return cachedTextEncoder.encodeInto(arg, view);
}
    : function (arg, view) {
    const buf = cachedTextEncoder.encode(arg);
    view.set(buf);
    return {
        read: arg.length,
        written: buf.length
    };
});
function passStringToWasm0(arg, malloc, realloc) {
    if (realloc === undefined) {
        const buf = cachedTextEncoder.encode(arg);
        const ptr = malloc(buf.length);
        getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
        WASM_VECTOR_LEN = buf.length;
        return ptr;
    }
    let len = arg.length;
    let ptr = malloc(len);
    const mem = getUint8Memory0();
    let offset = 0;
    for (; offset < len; offset++) {
        const code = arg.charCodeAt(offset);
        if (code > 0x7F) break;
        mem[ptr + offset] = code;
    }
    if (offset !== len) {
        if (offset !== 0) {
            arg = arg.slice(offset);
        }
        ptr = realloc(ptr, len, len = offset + arg.length * 3);
        const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
        const ret = encodeString(arg, view);
        offset += ret.written;
    }
    WASM_VECTOR_LEN = offset;
    return ptr;
}
/**
* @param {string} name
*/
export function greet(name) {
    const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
    const len0 = WASM_VECTOR_LEN;
    wasm.greet(ptr0, len0);
}
async function load(module, imports) {
    if (typeof Response === 'function' && module instanceof Response) {
        if (typeof WebAssembly.instantiateStreaming === 'function') {
            try {
                return await WebAssembly.instantiateStreaming(module, imports);
            } catch (e) {
                if (module.headers.get('Content-Type') != 'application/wasm') {
                    console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
                } else {
                    throw e;
                }
            }
        }
        const bytes = await module.arrayBuffer();
        return await WebAssembly.instantiate(bytes, imports);
    } else {
        const instance = await WebAssembly.instantiate(module, imports);
        if (instance instanceof WebAssembly.Instance) {
            return { instance, module };
        } else {
            return instance;
        }
    }
}
async function init(input) {
    if (typeof input === 'undefined') {
        input = new URL('wasm_bindgen_test_bg.wasm', import.meta.url);
    }
    const imports = {};
    imports.wbg = {};
    imports.wbg.__wbg_alert_0bebe9e6d7aece39 = function(arg0, arg1) {
        alert(getStringFromWasm0(arg0, arg1));
    };
    if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
        input = fetch(input);
    }
    const { instance, module } = await load(await input, imports);
    wasm = instance.exports;
    init.__wbindgen_wasm_module = module;
    return wasm;
}
export default init;
#[wasm_bindgen]をつけて宣言したgreet関数が用意されているのがわかります。
WasmとJavaScriptのデータのやり取りにはUint8Arrayなどの特定の型を使う必要があるため、文字列をエンコード及びデコードする仕組みも合わせて書き出されています。
また、Wasmの処理時にWasmのサイズの最適化も行ってくれます。
Rustがデフォルトで吐き出すWasmにはリリースビルドでもデバッグ用情報などが含まれており、かなりサイズが大きいものとなります。
例えば先のmain.rsはcargo build --releaseした場合、私の手元の環境では1655KBのWasmが吐き出されました。
これをwasm-bindgen-cliに食べさせた結果吐き出されるWasmは26KBでした。
大きくファイルサイズが減っていることがわかります。
Trunkを使う場合、wasm-bindgenの適用は勝手にやってくれるので、直接wasm-bindgen-cliを叩く必要はないかもしれません。
js_sys
js_sysはJavaScriptの型をRustで扱うためのクレートです。
JavaScriptのNumber型やJsString型などを提供します。
web_sys
web_sysはブラウザのAPIやブラウザ固有の型をRustで表現したものとなります。
HtmlInputElementやHtmlDivElementなどのブラウザ固有の型を扱う際に必要になります。
特にEventTargetを特定の型として取得する場合など、ダイナミックなキャストが必要になる場面も多く、その場合dyn_castなどを使います。
dyn_castはResult型を返すので、dyn_castとunwrapが入り乱れるなかなか治安の悪いコードを書くことになります。
js_sysやweb_sysでまるでWasmの中から直接JavaScriptの値やDOMを触っているような書き味でプログラムをかけますが、裏側ではJavaScriptのグルーコードを大量に生成してwasmにバインドしたそれらの関数の呼び出しなどに振り替えているようなので、WasmとJavaScriptの世界のやり取りが必要なためそこまで効率は良くないかもしれません。
「WebAssembly Reference Types」を利用すると生成されるJavaScriptのグルーコードが減り、効率も多少良くなることが期待されます。
「WebAssembly Reference Types」については次の記事がよくまとまっていて参考になります。
2022年6月11日の現状ではTrunkを使うとこのreference typesはうまく動きません。
Trunkにはdata-reference-typesという属性が指定できるようになっていますが、これによる指定ではwasm-bindgenのオプションのみ切り替わり、wasm-optのオプションが渡されないためリリースビルドでエラーが出てしまいます。
この問題についてはこちらのPRで直りそうに見えますが、現状まだ取り込まれていないようです。
wasm-bindgen-futures
Wasm環境下ではAtomicなオブジェクトを標準で使うのはまだ整備されていないため、ArcやMutexなどの仕様が制限されます。
それによってtokioなどの非同期ランタイムがWasm上ではうまく動きません。
wasm-bindgen-futuresはWasm環境下でも動く非同期ランタイムを提供します。
この非同期ランタイムはJavaScriptのPromiseの実行と結びついており、JavaScriptのPromiseとRustのFutureを相互に変換するような仕組みも用意してくれます。
gloo
WasmからDOMを操作したり、ブラウザのAPIを利用したりする際には、決まりきったコードを何度も書く必要が出てきます。
そのような処理を切り出して、ブラウザAPIをRustから叩く際の辛さを軽減してくれるライブラリです。
serde-wasm-bindgen
前述したserde-serializeというfeatureはJsValueとRustの値のやり取りにJSONのシリアライズとデシリアライズの機構を使っていました。
これは数値型などの直接扱えるものでもJSONを経由しているということで若干のムダがあります。
こちらのserde-wasm-bindgenはJSONを経由せずに直接やり取りできるものはやり取りするため、コードサイズが小さくなったりMapやSetをやり取りできるあたりが優れているとのことです。
wasm-pack
wasm-packはwasm-bindgenをラップしたより扱いやすいCLIツールです。
次のようにしてインストールが可能です。
$ cargo install wasm-pack
wasm-packを使うことで、ビルドしてwasm-bindgen-cliでさらに変換処理を行い、npmで配布可能なパッケージにするという多段階必要なビルド手順をまとめることが可能です。
またnewコマンドのようなテンプレートから生成する機能などもあり、より手軽にWasmの実行を行えます。
後述のTrunkとの違いは、wasm-packはwebpackなどのJavaScript側で使われるバンドラーなどと合わせて使うことが想定されていることです。
webpackと合わせて使わない場合には今回のテーマであり後述するTrunkを利用したほうがより簡単にWasmの実行を行えます。
wasm-opt
binaryenというリポジトリでwasm-optというツール含むいくつかのツールが作られています。
wasm-optはその名の通りWasmの最適化をしてくれるツールです。
与えるオプションによって実行速度の最適化ではなくファイルサイズの最適化ができます。
後述のTrunkに組み込まれていて、直接使うことなく最適化を行えます。
前述のmain.rsをwasm-bindgenに通したあとの26KBのWasmを、さらにwasm-optに最適化オプション-Ozのファイルサイズを小さくするような設定でかけてみると、17KBとなりました。
twiggy
twiggyはWasmバイナリファイルの内訳を表示することなどができます。
ファイルサイズの確認などに使えます。
上記main.rsをリリースビルドしたWasmをtwiggy topにかけてみた結果は次のとおりです。
twiggy top main.wasm
$ twiggy top .\target\wasm32-unknown-unknown\release\wasm_bindgen_test.wasm
 Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        599355 ┊    35.39% ┊ custom section '.debug_str'
        384623 ┊    22.71% ┊ custom section '.debug_info'
        295700 ┊    17.46% ┊ custom section '.debug_line'
        214568 ┊    12.67% ┊ custom section '.debug_pubnames'
        162280 ┊     9.58% ┊ custom section '.debug_ranges'
          8777 ┊     0.52% ┊ "function names" subsection
          4917 ┊     0.29% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::malloc::hcec496a2198179fe
          3932 ┊     0.23% ┊ custom section '.debug_abbrev'
          1429 ┊     0.08% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::free::h5fba2897807212aa
          1119 ┊     0.07% ┊ __rdl_realloc
          1062 ┊     0.06% ┊ core::str::count::do_count_chars::h8068e62995a060d4
          1031 ┊     0.06% ┊ core::fmt::Formatter::pad_integral::ha4f8dd1eb5755fda
           987 ┊     0.06% ┊ core::fmt::Formatter::pad::hc84bfca380790d9b
           770 ┊     0.05% ┊ data[0]
           727 ┊     0.04% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::dispose_chunk::h15f89ab1d45de9ae
           704 ┊     0.04% ┊ core::fmt::write::h3e26ed3eda73f0a3
           558 ┊     0.03% ┊ alloc::fmt::format::h588637f2f2183a4d
           501 ┊     0.03% ┊ dlmalloc::Dlmalloc<A>::malloc::hecadd78677587853
           494 ┊     0.03% ┊ __externref_table_alloc
           393 ┊     0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::release_unused_segments::h4826643b506d455c
           378 ┊     0.02% ┊ <alloc::string::String as core::fmt::Write>::write_char::hfcad3e975f1a678c
           376 ┊     0.02% ┊ alloc::string::String::push::he882a8f290dcb8c3
           364 ┊     0.02% ┊ core::fmt::num::imp::fmt_u64::h0c2fe44c27dae252
           352 ┊     0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::insert_large_chunk::h0ab04c16e556807e
           346 ┊     0.02% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::unlink_large_chunk::h3cd39bebabb3864d
           324 ┊     0.02% ┊ compiler_builtins::mem::memcpy::h78a567d3a58ab6e5
           324 ┊     0.02% ┊ custom section '.debug_pubtypes'
           321 ┊     0.02% ┊ __externref_heap_live_count
           317 ┊     0.02% ┊ __externref_table_dealloc
           308 ┊     0.02% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::take_box::h5fff44acdfbac4e7
           302 ┊     0.02% ┊ std::panicking::rust_panic_with_hook::he2a025723e105e28
           263 ┊     0.02% ┊ custom section '__wasm_bindgen_unstable'
           222 ┊     0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h2d7a97b6f3432e07
           222 ┊     0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h20a6726722873456
           222 ┊     0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h1397f88c4b936258
           222 ┊     0.01% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h00dea0a6d40548b6
           203 ┊     0.01% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::get::h79854d279d39b63d
           194 ┊     0.01% ┊ std::panicking::begin_panic_handler::{{closure}}::hd9f8c213ec91b9d5
           189 ┊     0.01% ┊ greet
           184 ┊     0.01% ┊ alloc::raw_vec::finish_grow::h98b255e8c87ba6ac
           184 ┊     0.01% ┊ alloc::raw_vec::finish_grow::h7642e1a95a96c333
           157 ┊     0.01% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::init_top::h18355a6f078d958f
           150 ┊     0.01% ┊ core::result::unwrap_failed::h68fdaca771c68bb6
           134 ┊     0.01% ┊ std::alloc::default_alloc_error_hook::h0876b7eb4919815d
           118 ┊     0.01% ┊ <&mut W as core::fmt::Write>::write_fmt::he72a95b1e7bc46cb
           118 ┊     0.01% ┊ <&mut W as core::fmt::Write>::write_fmt::hcb1df0cddb10ef35
            94 ┊     0.01% ┊ core::fmt::Formatter::pad_integral::write_prefix::h9ddec898718cb90a
            91 ┊     0.01% ┊ rust_begin_unwind
            90 ┊     0.01% ┊ <&mut W as core::fmt::Write>::write_str::h3169351e95b802c7
            90 ┊     0.01% ┊ <&mut W as core::fmt::Write>::write_str::hd4b6ba77fb1193cc
            86 ┊     0.01% ┊ core::panicking::panic::hc28e7cc2aa792341
            80 ┊     0.00% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::take_box::h8e753108593700f0
            80 ┊     0.00% ┊ alloc::raw_vec::capacity_overflow::h1de937e4490b6dee
            78 ┊     0.00% ┊ core::panicking::panic_fmt::hb02133958c1e7d35
            67 ┊     0.00% ┊ import __wbindgen_externref_xform__::__wbindgen_externref_table_set_null
            67 ┊     0.00% ┊ custom section 'producers'
            63 ┊     0.00% ┊ import __wbindgen_externref_xform__::__wbindgen_externref_table_grow
            60 ┊     0.00% ┊ __wbindgen_describe___wbg_alert_0bebe9e6d7aece39
            59 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::alloc::h8b3509d622dedd6b
            56 ┊     0.00% ┊ import __wbindgen_placeholder__::__wbg_alert_0bebe9e6d7aece39
            55 ┊     0.00% ┊ __wbindgen_malloc
            51 ┊     0.00% ┊ export "__wbindgen_describe___wbg_alert_0bebe9e6d7aece39"
            51 ┊     0.00% ┊ rust_panic
            49 ┊     0.00% ┊ __externref_drop_slice
            47 ┊     0.00% ┊ import __wbindgen_placeholder__::__wbindgen_describe
            44 ┊     0.00% ┊ __wbindgen_realloc
            44 ┊     0.00% ┊ core::ptr::drop_in_place<std::error::<impl core::convert::From<alloc::string::String> for alloc::boxed::Box<dyn std::error::Error+core::marker::Sync+core::marker::Send>>::from::StringError>::h9ce0522b145fe6fa
            44 ┊     0.00% ┊ core::ptr::drop_in_place<std::panicking::begin_panic_handler::PanicPayload>::h636ad6d68e279e0d
            41 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::set_inuse::hd80515990c160bc8
            40 ┊     0.00% ┊ dlmalloc::dlmalloc::Segment::holds::h1a60be87238e9919
            39 ┊     0.00% ┊ rust_oom
            37 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::set_free_with_pinuse::h64fe80d61b111714
            36 ┊     0.00% ┊ custom section 'name' headers
            35 ┊     0.00% ┊ <core::fmt::Error as core::fmt::Debug>::fmt::hb67b0fb623137665
            34 ┊     0.00% ┊ core::option::Option<T>::unwrap::haa480509e27ff8fc
            32 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse::hb9f654c37e5fb327
            31 ┊     0.00% ┊ elem[0]
            30 ┊     0.00% ┊ export "__externref_heap_live_count"
            30 ┊     0.00% ┊ core::option::Option<T>::unwrap::h3bbfb90b442ebef6
            30 ┊     0.00% ┊ dlmalloc::dlmalloc::TreeChunk::leftmost_child::h8bd9454cc3d402c7
            28 ┊     0.00% ┊ export "__wbindgen_describe_greet"
            28 ┊     0.00% ┊ export "__externref_table_dealloc"
            27 ┊     0.00% ┊ custom section '__wasm_bindgen_unstable' headers
            26 ┊     0.00% ┊ export "__externref_table_alloc"
            26 ┊     0.00% ┊ __wbindgen_exn_store
            26 ┊     0.00% ┊ std::sys_common::backtrace::__rust_end_short_backtrace::h6efd730283875809
            26 ┊     0.00% ┊ <&T as core::fmt::Debug>::fmt::hea96acd558b28457
            25 ┊     0.00% ┊ export "__externref_drop_slice"
            25 ┊     0.00% ┊ __rust_realloc
            24 ┊     0.00% ┊ __wbindgen_free
            24 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk::h11a8a5342df751be
            23 ┊     0.00% ┊ export "__wbindgen_exn_store"
            22 ┊     0.00% ┊ <&T as core::fmt::Display>::fmt::hcaadeff9a1654879
            22 ┊     0.00% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::get::h486eccde219d443e
            22 ┊     0.00% ┊ <&T as core::fmt::Display>::fmt::h8228500dd0a93de5
            21 ┊     0.00% ┊ export "__wbindgen_realloc"
            21 ┊     0.00% ┊ __rust_alloc
            20 ┊     0.00% ┊ export "__wbindgen_malloc"
            20 ┊     0.00% ┊ <&mut W as core::fmt::Write>::write_char::h735ba2e2255ac07c
            20 ┊     0.00% ┊ dlmalloc::dlmalloc::leftshift_for_tree_index::h6fffd47072ccebc0
            20 ┊     0.00% ┊ custom section '.debug_pubnames' headers
            19 ┊     0.00% ┊ <&mut W as core::fmt::Write>::write_char::h7f2928ac137cbae7
            19 ┊     0.00% ┊ core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt::h6bf974e8791b3fa6
            19 ┊     0.00% ┊ custom section '.debug_pubtypes' headers
            18 ┊     0.00% ┊ export "__wbindgen_free"
            18 ┊     0.00% ┊ dlmalloc::dlmalloc::align_up::hf1f4ea6608931a25
            18 ┊     0.00% ┊ custom section '.debug_ranges' headers
            17 ┊     0.00% ┊ __rust_dealloc
            17 ┊     0.00% ┊ dlmalloc::dlmalloc::left_bits::h4c3ee1c04a9d948c
            17 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::clear_pinuse::h28b4b6bfa0365301
            17 ┊     0.00% ┊ custom section '.debug_abbrev' headers
            16 ┊     0.00% ┊ <str as core::fmt::Display>::fmt::he02814d332326528
            16 ┊     0.00% ┊ memcpy
            16 ┊     0.00% ┊ custom section '.debug_info' headers
            16 ┊     0.00% ┊ custom section '.debug_line' headers
            15 ┊     0.00% ┊ __rust_alloc_error_handler
            15 ┊     0.00% ┊ <T as core::any::Any>::type_id::hf1eb4553966c7029
            15 ┊     0.00% ┊ <T as core::any::Any>::type_id::hf86124a39f31439b
            15 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::cinuse::hfcc18d9ee069b807
            15 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::inuse::h86972c896758fa35
            15 ┊     0.00% ┊ dlmalloc::dlmalloc::Segment::top::had8e50e872afff9d
            15 ┊     0.00% ┊ core::intrinsics::const_eval_select::hbff2fd2057209df4
            15 ┊     0.00% ┊ core::ops::function::FnOnce::call_once::h7538d6968a96c4c6
            15 ┊     0.00% ┊ alloc::alloc::handle_alloc_error::rt_error::h215dddd0f4495f99
            15 ┊     0.00% ┊ alloc::alloc::handle_alloc_error::h0693183370a7902c
            15 ┊     0.00% ┊ __rg_oom
            15 ┊     0.00% ┊ core::ops::function::FnOnce::call_once::h5753b14cff916f0e
            15 ┊     0.00% ┊ <T as core::any::Any>::type_id::hc91c1766c0a8e26b
            15 ┊     0.00% ┊ custom section '.debug_str' headers
            14 ┊     0.00% ┊ export "__heap_base"
            14 ┊     0.00% ┊ __rdl_alloc
            14 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk::h81fc9155883489ea
            13 ┊     0.00% ┊ export "__data_end"
            13 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::mmapped::h04354a447c7ef83b
            12 ┊     0.00% ┊ <() as wasm_bindgen::describe::WasmDescribe>::describe::h8066b3287422c15b
            12 ┊     0.00% ┊ <str as wasm_bindgen::describe::WasmDescribe>::describe::h09e5dc149b174418
            12 ┊     0.00% ┊ __rdl_dealloc
            12 ┊     0.00% ┊ dlmalloc::dlmalloc::least_bit::h5164fc99df6558f5
            12 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::size::ha342d078107e0f53
            12 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::pinuse::h3e366cef7e528bba
            12 ┊     0.00% ┊ dlmalloc::dlmalloc::Segment::is_extern::h6fdd496f2978bb35
            12 ┊     0.00% ┊ dlmalloc::dlmalloc::Segment::sys_flags::h4d6b01219f9e07b9
            12 ┊     0.00% ┊ custom section 'producers' headers
            11 ┊     0.00% ┊ wasm_bindgen::externref::internal_error::h1e4496ca9551d147
            11 ┊     0.00% ┊ wasm_bindgen::__rt::malloc_failure::h8137027072480bce
            11 ┊     0.00% ┊ code section headers
            10 ┊     0.00% ┊ type[13]: (i32, i32, i32, i32, i32, i32) -> i32
            10 ┊     0.00% ┊ wasm_bindgen::__rt::link_mem_intrinsics::h84678cad5a3f00f2
             9 ┊     0.00% ┊ type[12]: (i32, i32, i32, i32, i32) -> i32
             9 ┊     0.00% ┊ export "memory"
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::plus_offset::hf594a71617f2958c
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::minus_offset::ha660e14327ac3e4c
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::to_mem::h4b386d4e48d965cf
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::from_mem::h75b6b5095597031a
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::TreeChunk::next::h6a3f651c010e6975
             9 ┊     0.00% ┊ dlmalloc::dlmalloc::TreeChunk::prev::h052e4d2e0cbc3ff0
             9 ┊     0.00% ┊ core::panic::panic_info::PanicInfo::message::h102fddb6becb8eab
             9 ┊     0.00% ┊ core::panic::panic_info::PanicInfo::location::h5dfcade149d8a598
             9 ┊     0.00% ┊ core::panic::panic_info::PanicInfo::can_unwind::hf0853bc09675a7a1
             8 ┊     0.00% ┊ type[7]: (i32, i32, i32, i32) -> i32
             8 ┊     0.00% ┊ type[11]: (i32, i32, i32, i32, i32) -> nil
             8 ┊     0.00% ┊ global[0]
             8 ┊     0.00% ┊ global[1]
             8 ┊     0.00% ┊ global[2]
             8 ┊     0.00% ┊ export "greet"
             8 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::page_size::h88a1bbbf4b8674f2
             8 ┊     0.00% ┊ wasm magic bytes
             7 ┊     0.00% ┊ type[1]: (i32, i32, i32) -> i32
             7 ┊     0.00% ┊ type[10]: (i32, i32, i32, i32) -> nil
             7 ┊     0.00% ┊ type[14]: (i64, i32, i32) -> i32
             6 ┊     0.00% ┊ type[2]: (i32, i32) -> i32
             6 ┊     0.00% ┊ type[6]: (i32, i32, i32) -> nil
             6 ┊     0.00% ┊ std::process::abort::hbba08b3d6df850f8
             6 ┊     0.00% ┊ __rust_start_panic
             6 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::fencepost_head::h343fc8d31cab4021
             6 ┊     0.00% ┊ dlmalloc::dlmalloc::Chunk::mem_offset::hb26f0a8f126c0579
             6 ┊     0.00% ┊ dlmalloc::dlmalloc::TreeChunk::chunk::h9cbb25ca6296593a
             6 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::remap::h0979387267a4a643
             6 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free_part::hef5dee6eb24bcc8c
             6 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free::h0aa881b9e76b9b02
             6 ┊     0.00% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::can_release_part::hc2a2319ea9025de0
             5 ┊     0.00% ┊ type[0]: (i32, i32) -> nil
             5 ┊     0.00% ┊ type[4]: (i32) -> i32
             5 ┊     0.00% ┊ type[9]: (i32) -> i64
             4 ┊     0.00% ┊ type[3]: (i32) -> nil
             4 ┊     0.00% ┊ type[8]: () -> i32
             4 ┊     0.00% ┊ import section headers
             4 ┊     0.00% ┊ table[0]
             4 ┊     0.00% ┊ export section headers
             4 ┊     0.00% ┊ wasm_bindgen::externref::link_intrinsics::h8e3c0da2384b97d7
             4 ┊     0.00% ┊ core::ptr::drop_in_place<&mut std::io::Write::write_fmt::Adapter<alloc::vec::Vec<u8>>>::ha5213606bfbb1ca2
             4 ┊     0.00% ┊ core::ptr::drop_in_place<&u8>::h52ad2d112c7e2ce3
             4 ┊     0.00% ┊ core::ptr::drop_in_place<&core::iter::adapters::copied::Copied<core::slice::iter::Iter<u8>>>::h0e2bcd53588f6395
             4 ┊     0.00% ┊ data section headers
             3 ┊     0.00% ┊ type[5]: () -> nil
             3 ┊     0.00% ┊ type section headers
             3 ┊     0.00% ┊ table section headers
             3 ┊     0.00% ┊ memory section headers
             3 ┊     0.00% ┊ global section headers
             3 ┊     0.00% ┊ element section headers
             2 ┊     0.00% ┊ memory[0]
             2 ┊     0.00% ┊ "function names" subsection
             2 ┊     0.00% ┊ "function names" subsection
       1693789 ┊   100.00% ┊ Σ [203 Total Rows]
リリースビルドしたにも関わらずデバッグ情報がWasmに入っています。
wasm-bindgen-cliを通したあとのwasmにtwiggyを使ってみると次の通り。
twiggy top wasn_bindgen_test_bg.wasm
$ twiggy top .\.pkg\wasm_bindgen_test_bg.wasm
 Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          6921 ┊    26.25% ┊ "function names" subsection
          4015 ┊    15.23% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::malloc::hcec496a2198179fe
          1185 ┊     4.49% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::free::h5fba2897807212aa
          1062 ┊     4.03% ┊ core::str::count::do_count_chars::h8068e62995a060d4
           979 ┊     3.71% ┊ core::fmt::Formatter::pad_integral::ha4f8dd1eb5755fda
           959 ┊     3.64% ┊ core::fmt::Formatter::pad::hc84bfca380790d9b
           881 ┊     3.34% ┊ __rdl_realloc
           770 ┊     2.92% ┊ data[0]
           664 ┊     2.52% ┊ core::fmt::write::h3e26ed3eda73f0a3
           623 ┊     2.36% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::dispose_chunk::h15f89ab1d45de9ae
           522 ┊     1.98% ┊ alloc::fmt::format::h588637f2f2183a4d
           385 ┊     1.46% ┊ dlmalloc::Dlmalloc<A>::malloc::hecadd78677587853
           354 ┊     1.34% ┊ <alloc::string::String as core::fmt::Write>::write_char::hfcad3e975f1a678c
           352 ┊     1.34% ┊ alloc::string::String::push::he882a8f290dcb8c3
           341 ┊     1.29% ┊ core::fmt::num::imp::fmt_u64::h0c2fe44c27dae252
           324 ┊     1.23% ┊ compiler_builtins::mem::memcpy::h78a567d3a58ab6e5
           322 ┊     1.22% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::release_unused_segments::h4826643b506d455c
           321 ┊     1.22% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::unlink_large_chunk::h3cd39bebabb3864d
           319 ┊     1.21% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::insert_large_chunk::h0ab04c16e556807e
           282 ┊     1.07% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::take_box::h5fff44acdfbac4e7
           257 ┊     0.97% ┊ std::panicking::rust_panic_with_hook::he2a025723e105e28
           198 ┊     0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h2d7a97b6f3432e07
           198 ┊     0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h20a6726722873456
           198 ┊     0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve::do_reserve_and_handle::h1397f88c4b936258
           198 ┊     0.75% ┊ alloc::raw_vec::RawVec<T,A>::reserve_for_push::h00dea0a6d40548b6
           185 ┊     0.70% ┊ <std::panicking::begin_panic_handler::PanicPayload as core::panic::BoxMeUp>::get::h79854d279d39b63d
           176 ┊     0.67% ┊ alloc::raw_vec::finish_grow::h98b255e8c87ba6ac
           176 ┊     0.67% ┊ alloc::raw_vec::finish_grow::h7642e1a95a96c333
           159 ┊     0.60% ┊ std::panicking::begin_panic_handler::{{closure}}::hd9f8c213ec91b9d5
           156 ┊     0.59% ┊ greet
           128 ┊     0.49% ┊ core::result::unwrap_failed::h68fdaca771c68bb6
           118 ┊     0.45% ┊ dlmalloc::dlmalloc::Dlmalloc<A>::init_top::h18355a6f078d958f
           109 ┊     0.41% ┊ std::alloc::default_alloc_error_hook::h0876b7eb4919815d
           101 ┊     0.38% ┊ <&mut W as core::fmt::Write>::write_fmt::he72a95b1e7bc46cb
           101 ┊     0.38% ┊ <&mut W as core::fmt::Write>::write_fmt::hcb1df0cddb10ef35
           101 ┊     0.38% ┊ custom section 'producers'
            86 ┊     0.33% ┊ core::fmt::Formatter::pad_integral::write_prefix::h9ddec898718cb90a
            82 ┊     0.31% ┊ <&mut W as core::fmt::Write>::write_str::h3169351e95b802c7
            82 ┊     0.31% ┊ <&mut W as core::fmt::Write>::write_str::hd4b6ba77fb1193cc
            73 ┊     0.28% ┊ core::panicking::panic::hc28e7cc2aa792341
            71 ┊     0.27% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::take_box::h8e753108593700f0
            65 ┊     0.25% ┊ alloc::raw_vec::capacity_overflow::h1de937e4490b6dee
            64 ┊     0.24% ┊ core::panicking::panic_fmt::hb02133958c1e7d35
            62 ┊     0.24% ┊ rust_begin_unwind
            59 ┊     0.22% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::alloc::h8b3509d622dedd6b
            47 ┊     0.18% ┊ __wbindgen_malloc
            41 ┊     0.16% ┊ dlmalloc::dlmalloc::Chunk::set_inuse::hd80515990c160bc8
            40 ┊     0.15% ┊ core::ptr::drop_in_place<std::error::<impl core::convert::From<alloc::string::String> for alloc::boxed::Box<dyn std::error::Error+core::marker::Sync+core::marker::Send>>::from::StringError>::h9ce0522b145fe6fa
            40 ┊     0.15% ┊ core::ptr::drop_in_place<std::panicking::begin_panic_handler::PanicPayload>::h636ad6d68e279e0d
            40 ┊     0.15% ┊ dlmalloc::dlmalloc::Segment::holds::h1a60be87238e9919
            38 ┊     0.14% ┊ rust_panic
            37 ┊     0.14% ┊ dlmalloc::dlmalloc::Chunk::set_free_with_pinuse::h64fe80d61b111714
            36 ┊     0.14% ┊ __wbindgen_realloc
            35 ┊     0.13% ┊ import wbg::__wbg_alert_0bebe9e6d7aece39
            32 ┊     0.12% ┊ dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse::hb9f654c37e5fb327
            30 ┊     0.11% ┊ elem[0]
            30 ┊     0.11% ┊ dlmalloc::dlmalloc::TreeChunk::leftmost_child::h8bd9454cc3d402c7
            30 ┊     0.11% ┊ <core::fmt::Error as core::fmt::Debug>::fmt::hb67b0fb623137665
            28 ┊     0.11% ┊ rust_oom
            28 ┊     0.11% ┊ core::option::Option<T>::unwrap::haa480509e27ff8fc
            25 ┊     0.09% ┊ core::option::Option<T>::unwrap::h3bbfb90b442ebef6
            24 ┊     0.09% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk::h11a8a5342df751be
            22 ┊     0.08% ┊ std::sys_common::backtrace::__rust_end_short_backtrace::h6efd730283875809
            22 ┊     0.08% ┊ <&T as core::fmt::Debug>::fmt::hea96acd558b28457
            21 ┊     0.08% ┊ export "__wbindgen_realloc"
            21 ┊     0.08% ┊ __rust_realloc
            21 ┊     0.08% ┊ <std::panicking::begin_panic_handler::StrPanicPayload as core::panic::BoxMeUp>::get::h486eccde219d443e
            20 ┊     0.08% ┊ export "__wbindgen_malloc"
            20 ┊     0.08% ┊ dlmalloc::dlmalloc::leftshift_for_tree_index::h6fffd47072ccebc0
            18 ┊     0.07% ┊ dlmalloc::dlmalloc::align_up::hf1f4ea6608931a25
            18 ┊     0.07% ┊ <&T as core::fmt::Display>::fmt::hcaadeff9a1654879
            18 ┊     0.07% ┊ <&T as core::fmt::Display>::fmt::h8228500dd0a93de5
            17 ┊     0.06% ┊ dlmalloc::dlmalloc::left_bits::h4c3ee1c04a9d948c
            17 ┊     0.06% ┊ __rust_alloc
            17 ┊     0.06% ┊ dlmalloc::dlmalloc::Chunk::clear_pinuse::h28b4b6bfa0365301
            16 ┊     0.06% ┊ <&mut W as core::fmt::Write>::write_char::h735ba2e2255ac07c
            16 ┊     0.06% ┊ custom section 'producers' headers
            15 ┊     0.06% ┊ dlmalloc::dlmalloc::Chunk::cinuse::hfcc18d9ee069b807
            15 ┊     0.06% ┊ dlmalloc::dlmalloc::Chunk::inuse::h86972c896758fa35
            15 ┊     0.06% ┊ dlmalloc::dlmalloc::Segment::top::had8e50e872afff9d
            15 ┊     0.06% ┊ <&mut W as core::fmt::Write>::write_char::h7f2928ac137cbae7
            15 ┊     0.06% ┊ core::ops::function::FnOnce::call_once::h5753b14cff916f0e
            15 ┊     0.06% ┊ core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt::h6bf974e8791b3fa6
            15 ┊     0.06% ┊ <T as core::any::Any>::type_id::hf1eb4553966c7029
            15 ┊     0.06% ┊ <T as core::any::Any>::type_id::hf86124a39f31439b
            15 ┊     0.06% ┊ <T as core::any::Any>::type_id::hc91c1766c0a8e26b
            14 ┊     0.05% ┊ dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk::h81fc9155883489ea
            14 ┊     0.05% ┊ code section headers
            13 ┊     0.05% ┊ __rust_dealloc
            13 ┊     0.05% ┊ dlmalloc::dlmalloc::Chunk::mmapped::h04354a447c7ef83b
            12 ┊     0.05% ┊ dlmalloc::dlmalloc::least_bit::h5164fc99df6558f5
            12 ┊     0.05% ┊ dlmalloc::dlmalloc::Chunk::size::ha342d078107e0f53
            12 ┊     0.05% ┊ dlmalloc::dlmalloc::Chunk::pinuse::h3e366cef7e528bba
            12 ┊     0.05% ┊ dlmalloc::dlmalloc::Segment::is_extern::h6fdd496f2978bb35
            12 ┊     0.05% ┊ dlmalloc::dlmalloc::Segment::sys_flags::h4d6b01219f9e07b9
            12 ┊     0.05% ┊ <str as core::fmt::Display>::fmt::he02814d332326528
            12 ┊     0.05% ┊ memcpy
            11 ┊     0.04% ┊ __rust_alloc_error_handler
            11 ┊     0.04% ┊ core::intrinsics::const_eval_select::hbff2fd2057209df4
            11 ┊     0.04% ┊ core::ops::function::FnOnce::call_once::h7538d6968a96c4c6
            11 ┊     0.04% ┊ alloc::alloc::handle_alloc_error::rt_error::h215dddd0f4495f99
            11 ┊     0.04% ┊ alloc::alloc::handle_alloc_error::h0693183370a7902c
            11 ┊     0.04% ┊ __rg_oom
            11 ┊     0.04% ┊ custom section 'name' headers
            10 ┊     0.04% ┊ type[13]: (i32, i32, i32, i32, i32, i32) -> i32
            10 ┊     0.04% ┊ __rdl_alloc
             9 ┊     0.03% ┊ type[12]: (i32, i32, i32, i32, i32) -> i32
             9 ┊     0.03% ┊ export "memory"
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::Chunk::plus_offset::hf594a71617f2958c
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::Chunk::minus_offset::ha660e14327ac3e4c
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::Chunk::to_mem::h4b386d4e48d965cf
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::Chunk::from_mem::h75b6b5095597031a
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::TreeChunk::next::h6a3f651c010e6975
             9 ┊     0.03% ┊ dlmalloc::dlmalloc::TreeChunk::prev::h052e4d2e0cbc3ff0
             9 ┊     0.03% ┊ core::panic::panic_info::PanicInfo::message::h102fddb6becb8eab
             9 ┊     0.03% ┊ core::panic::panic_info::PanicInfo::location::h5dfcade149d8a598
             9 ┊     0.03% ┊ core::panic::panic_info::PanicInfo::can_unwind::hf0853bc09675a7a1
             8 ┊     0.03% ┊ type[10]: (i32, i32, i32, i32) -> i32
             8 ┊     0.03% ┊ type[11]: (i32, i32, i32, i32, i32) -> nil
             8 ┊     0.03% ┊ global[0]
             8 ┊     0.03% ┊ export "greet"
             8 ┊     0.03% ┊ __rdl_dealloc
             8 ┊     0.03% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::page_size::h88a1bbbf4b8674f2
             8 ┊     0.03% ┊ wasm magic bytes
             7 ┊     0.03% ┊ type[8]: (i32, i32, i32) -> i32
             7 ┊     0.03% ┊ type[9]: (i32, i32, i32, i32) -> nil
             7 ┊     0.03% ┊ type[14]: (i64, i32, i32) -> i32
             7 ┊     0.03% ┊ type section headers
             7 ┊     0.03% ┊ import section headers
             7 ┊     0.03% ┊ table section headers
             7 ┊     0.03% ┊ memory section headers
             7 ┊     0.03% ┊ global section headers
             7 ┊     0.03% ┊ export section headers
             7 ┊     0.03% ┊ element section headers
             7 ┊     0.03% ┊ wasm_bindgen::__rt::malloc_failure::h8137027072480bce
             7 ┊     0.03% ┊ data section headers
             6 ┊     0.02% ┊ type[6]: (i32, i32) -> i32
             6 ┊     0.02% ┊ type[7]: (i32, i32, i32) -> nil
             6 ┊     0.02% ┊ dlmalloc::dlmalloc::Chunk::fencepost_head::h343fc8d31cab4021
             6 ┊     0.02% ┊ dlmalloc::dlmalloc::Chunk::mem_offset::hb26f0a8f126c0579
             6 ┊     0.02% ┊ dlmalloc::dlmalloc::TreeChunk::chunk::h9cbb25ca6296593a
             6 ┊     0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::remap::h0979387267a4a643
             6 ┊     0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free_part::hef5dee6eb24bcc8c
             6 ┊     0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::free::h0aa881b9e76b9b02
             6 ┊     0.02% ┊ <dlmalloc::sys::System as dlmalloc::Allocator>::can_release_part::hc2a2319ea9025de0
             5 ┊     0.02% ┊ type[3]: (i32) -> i32
             5 ┊     0.02% ┊ type[4]: (i32) -> i64
             5 ┊     0.02% ┊ type[5]: (i32, i32) -> nil
             5 ┊     0.02% ┊ std::process::abort::hbba08b3d6df850f8
             5 ┊     0.02% ┊ __rust_start_panic
             4 ┊     0.02% ┊ type[1]: () -> i32
             4 ┊     0.02% ┊ type[2]: (i32) -> nil
             4 ┊     0.02% ┊ table[0]
             4 ┊     0.02% ┊ core::ptr::drop_in_place<&mut std::io::Write::write_fmt::Adapter<alloc::vec::Vec<u8>>>::ha5213606bfbb1ca2
             4 ┊     0.02% ┊ core::ptr::drop_in_place<&u8>::h52ad2d112c7e2ce3
             4 ┊     0.02% ┊ core::ptr::drop_in_place<&core::iter::adapters::copied::Copied<core::slice::iter::Iter<u8>>>::h0e2bcd53588f6395
             3 ┊     0.01% ┊ type[0]: () -> nil
             2 ┊     0.01% ┊ memory[0]
         26366 ┊   100.00% ┊ Σ [158 Total Rows]
デバッグ情報が消えました。
上位に残っているのは関数名のセクションです。
さらにwasm-optで最適化をかけたあとでは次のようになります。
twiggy top opt-wasm.wasm
$ twiggy top .\.pkg\opt-wasm.wasm
 Shallow Bytes │ Shallow % │ Item
───────────────┼───────────┼──────────────────────────────────────────
          4207 ┊    24.98% ┊ code[0]
          1904 ┊    11.30% ┊ code[2]
          1028 ┊     6.10% ┊ code[51]
           885 ┊     5.25% ┊ code[1]
           770 ┊     4.57% ┊ data[0]
           731 ┊     4.34% ┊ code[15]
           723 ┊     4.29% ┊ code[37]
           641 ┊     3.81% ┊ code[3]
           592 ┊     3.51% ┊ code[4]
           366 ┊     2.17% ┊ code[5]
           351 ┊     2.08% ┊ code[49]
           349 ┊     2.07% ┊ code[42]
           315 ┊     1.87% ┊ code[57]
           313 ┊     1.86% ┊ code[7]
           305 ┊     1.81% ┊ code[24]
           295 ┊     1.75% ┊ code[6]
           274 ┊     1.63% ┊ code[10]
           268 ┊     1.59% ┊ code[9]
           187 ┊     1.11% ┊ code[11]
           187 ┊     1.11% ┊ code[12]
           175 ┊     1.04% ┊ code[13]
           154 ┊     0.91% ┊ code[14]
           113 ┊     0.67% ┊ code[8]
           105 ┊     0.62% ┊ code[17]
           101 ┊     0.60% ┊ custom section 'producers'
            91 ┊     0.54% ┊ code[16]
            91 ┊     0.54% ┊ code[18]
            80 ┊     0.47% ┊ code[19]
            77 ┊     0.46% ┊ code[20]
            76 ┊     0.45% ┊ code[21]
            70 ┊     0.42% ┊ code[22]
            65 ┊     0.39% ┊ code[23]
            44 ┊     0.26% ┊ code[25]
            41 ┊     0.24% ┊ code[26]
            37 ┊     0.22% ┊ code[30]
            35 ┊     0.21% ┊ import wbg::__wbg_alert_0bebe9e6d7aece39
            34 ┊     0.20% ┊ code[28]
            32 ┊     0.19% ┊ code[27]
            32 ┊     0.19% ┊ code[29]
            32 ┊     0.19% ┊ code[31]
            30 ┊     0.18% ┊ elem[0]
            30 ┊     0.18% ┊ code[35]
            27 ┊     0.16% ┊ code[32]
            27 ┊     0.16% ┊ code[56]
            24 ┊     0.14% ┊ code[34]
            22 ┊     0.13% ┊ code[39]
            21 ┊     0.12% ┊ export "__wbindgen_realloc"
            21 ┊     0.12% ┊ code[43]
            20 ┊     0.12% ┊ export "__wbindgen_malloc"
            20 ┊     0.12% ┊ code[33]
            18 ┊     0.11% ┊ code[36]
            18 ┊     0.11% ┊ code[40]
            17 ┊     0.10% ┊ code[38]
            16 ┊     0.09% ┊ code[50]
            15 ┊     0.09% ┊ code[44]
            15 ┊     0.09% ┊ code[48]
            15 ┊     0.09% ┊ code[62]
            15 ┊     0.09% ┊ code[63]
            15 ┊     0.09% ┊ code[64]
            14 ┊     0.08% ┊ code[47]
            13 ┊     0.08% ┊ code[46]
            12 ┊     0.07% ┊ code[45]
            12 ┊     0.07% ┊ code[52]
            12 ┊     0.07% ┊ code[53]
            12 ┊     0.07% ┊ code[54]
            12 ┊     0.07% ┊ code[55]
            12 ┊     0.07% ┊ custom section 'producers' headers
            10 ┊     0.06% ┊ code[41]
             9 ┊     0.05% ┊ export "memory"
             9 ┊     0.05% ┊ code[58]
             9 ┊     0.05% ┊ code[59]
             9 ┊     0.05% ┊ code[60]
             9 ┊     0.05% ┊ code[61]
             8 ┊     0.05% ┊ type[8]: (i32, i32, i32, i32, i32) -> nil
             8 ┊     0.05% ┊ type[10]: (i32, i32, i32, i32) -> i32
             8 ┊     0.05% ┊ global[0]
             8 ┊     0.05% ┊ export "greet"
             8 ┊     0.05% ┊ wasm magic bytes
             7 ┊     0.04% ┊ type[2]: (i32, i32, i32) -> i32
             7 ┊     0.04% ┊ code section headers
             6 ┊     0.04% ┊ type[0]: (i32, i32) -> i32
             6 ┊     0.04% ┊ type[5]: (i32, i32, i32) -> nil
             5 ┊     0.03% ┊ type[1]: (i32, i32) -> nil
             5 ┊     0.03% ┊ type[3]: (i32) -> i32
             5 ┊     0.03% ┊ type[6]: (i32) -> i64
             5 ┊     0.03% ┊ code[65]
             4 ┊     0.02% ┊ type[4]: (i32) -> nil
             4 ┊     0.02% ┊ type[7]: () -> i32
             4 ┊     0.02% ┊ table[0]
             4 ┊     0.02% ┊ data section headers
             3 ┊     0.02% ┊ type[9]: () -> nil
             3 ┊     0.02% ┊ type section headers
             3 ┊     0.02% ┊ import section headers
             3 ┊     0.02% ┊ table section headers
             3 ┊     0.02% ┊ memory section headers
             3 ┊     0.02% ┊ global section headers
             3 ┊     0.02% ┊ export section headers
             3 ┊     0.02% ┊ element section headers
             2 ┊     0.01% ┊ memory[0]
         16844 ┊   100.00% ┊ Σ [99 Total Rows]
関数名のセクションも消えて、だいぶファイルサイズが最適化されていそうなことがわかります。
Trunk
Trunkはビルドツールの一種です。
RustとWasmを組み合わせて使うように作られていますが、Wasmの他にSassからCSSへのコンバートなどWebアプリを作るのに必要なビルド機能もいくつか対応しています。
現時点ではRustで書いたWasmをnpmパッケージ等にラップすることなく直接HTML上で実行したい場合、Trunkが最速で実行できると思います。
エントリーポイントとなるindex.htmlにRustのWasmをビルドして最適化処理をかけたものを読み込む処理を埋め込み、その他リソースの処理なども行った上で、開発用サーバーを立ててくれてブラウザの自動リロードにも対応してくれます。
次項で実際にTrunkを使っていきます。
Trunkを使ってみる
まずはRustのインストールを済ませておいてください。
次にcargp installでTrunkをインストールします。
$ cargo install --locked trunk
次にこのような空っぽのhtmlファイルをindex.htmlという名前でCargo.tomlの隣に配置します。
<!DOCTYPE html>
<html>
  <head></head>
</html>
このファイルがエントリーポイントとなります。
次にいくつかのパッケージを追加します。
cargo-editが入っている場合は次のコマンドを打ちます。
$ cargo add log wasm-logger
logはRustの一般的に使われているロギングのライブラリで、wasm-loggerはconsole.logにlogクレートのログの内容を流してくれるものです。
次にmain.rsに次のように書きます。
pub fn main() {
    wasm_logger::init(wasm_logger::Config::default());
    log::debug!("Hello, world!");
}
Trunkがwasm-bindgenとのつなぎ込みもやってくれるようなので、main関数を書くだけで良いです。
main関数はWasmをロードしたあとに勝手に走るようになっているようです。
ここまで書いたら次のコマンドを実行します。
$ trunk serve
これでビルドが走りサーバーが立ち上がります。
http://127.0.0.1:8080を開いて開発者ツールをみると次のようにHello, Worldが表示されていました。

wasm-optの最適化オプションを付けるにはindex.htmlに次のような指定をします。
<!DOCTYPE html>
<html>
  <head>
    <link data-trunk rel="rust" data-wasm-opt="z">
  </head>
</html>
trunk serve --releaseあるいはtrunk build --releaseとすることでリリースモードで実行すると、wasm-optが実行され、Wasmのサイズが小さくなって配信に向いた形になります。
おわりに
RustでWasmを書く際に使える周辺ライブラリをまとめ、その後Trunkで実際にWasmを作成し動かすところまでやりました。
今回の記事では試しませんでしたが、JavaScriptとWasmの間でのやり取りもwasm-bindgenによってだいぶ書きやすくなっています。
次回の記事ではYewというWasm用ライブラリをTrunkを使ってビルドしてみたいと思います。



Discussion
とても参考になりました!ありがとうございます✨