初級 getting-started

Wasmのデバッグ

Wasmのデバッグが異なる理由

RustがWasm内でパニックすると、ブラウザのコンソールには役に立たないunreachableエラーが表示されます。スタックトレースもエラーメッセージもありません。このレッスンでは、その問題を解決する方法を紹介します。

ステップ1:より良いパニックメッセージ

console_error_panic_hookを追加して、読みやすいパニックメッセージを取得します:

[dependencies]
console_error_panic_hook = "0.1"
wasm-bindgen = "0.2"
use wasm_bindgen::prelude::*;

#[wasm_bindgen(start)]
pub fn init() {
    // 起動時に一度だけ呼び出す
    console_error_panic_hook::set_once();
}

#[wasm_bindgen]
pub fn might_panic(x: i32) -> i32 {
    // フックなし: "unreachable"
    // フックあり: "panicked at 'index out of bounds: len is 3, index is 5'"
    let v = vec![1, 2, 3];
    v[x as usize]
}

ステップ2:Rustからのコンソールログ

シンプルな方法:web_sys::consoleを使用

use web_sys::console;

// 文字列をログ出力
console::log_1(&"Hello from Rust!".into());

// フォーマット付きログ
console::log_2(&"Value:".into(), &JsValue::from(42));

// 警告とエラー
console::warn_1(&"This is a warning".into());
console::error_1(&"This is an error".into());

よりクリーンな方法:ログマクロを作成

macro_rules! log {
    ($($t:tt)*) => {
        web_sys::console::log_1(
            &wasm_bindgen::JsValue::from_str(&format!($($t)*))
        );
    };
}

// 使用例:
log!("User {} logged in at {}", name, timestamp);
log!("Data: {:?}", my_vec);

ステップ3:ブラウザDevTools

ソースマップ

デバッグ情報付きでビルドすると、DevToolsでRustのソースコードを確認できます:

# デバッグビルド(バイナリが大きくなるが、デバッグ情報あり)
wasm-pack build --dev --target web

# リリースビルド(デバッグ情報なし)
wasm-pack build --target web

Networkタブ

.wasmファイルが正しく読み込まれているか確認します:

  • ステータスが200であること
  • Content-Typeがapplication/wasmであること
  • サイズで最適化が効いているか確認

Performanceタブ

Wasmの実行をプロファイリングします:

  1. DevTools → Performanceを開く
  2. Recordをクリック
  3. アプリを操作する
  4. 記録を停止
  5. フレームチャートで"wasm-function"エントリを探す

ステップ4:エラーハンドリングパターン

パニックの代わりにResultを返す

#[wasm_bindgen]
pub fn safe_divide(a: f64, b: f64) -> Result<f64, JsValue> {
    if b == 0.0 {
        Err(JsValue::from_str("Division by zero"))
    } else {
        Ok(a / b)
    }
}

JavaScript側では、try/catchになります:

try {
    const result = safe_divide(10, 0);
} catch (e) {
    console.error("Wasm error:", e); // "Division by zero"
}

カスタムエラー型

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct AppError {
    message: String,
    code: u32,
}

#[wasm_bindgen]
impl AppError {
    pub fn message(&self) -> String { self.message.clone() }
    pub fn code(&self) -> u32 { self.code }
}

よくあるデバッグチェックリスト

問題 原因 解決方法
コンソールにunreachable フックなしのRustパニック console_error_panic_hookを追加
.wasmファイルが読み込めない パスまたはMIMEタイプが間違い Networkタブを確認し、正しいContent-Typeで配信
読み込み時にLinkError インポートが不足 すべてのextern "C"インポートが満たされているか確認
RuntimeError: memory Wasmメモリ不足 メモリを増やすかメモリリークを修正
関数が見つからない エクスポートされていない #[wasm_bindgen]pubを追加
型が一致しない wasm-bindgenのバージョン不一致 JSグルーと.wasmが同じビルドのものか確認

試してみよう

Runをクリックして、デバッグ出力の例を確認しましょう。実際のWasmプロジェクトでは、println!console::log_1に置き換えてください。

試してみる

チャプタークイズ

すべての問題に正解してレッスンを完了しましょう