Rust + Wasm で『JS の数倍速い』ブラウザ処理を作る
Rust + WebAssembly は CPU 集約処理(画像/動画/暗号/物理計算等)で JS の数倍速いブラウザ処理を実現できます。本記事では編集部の視点で、実装と最適化を公開情報をもとに整理します。WebAssembly 実践 もご参考に。
主要ツールチェイン
(1) wasm-bindgen:JS/Wasm 相互運用。(2) wasm-pack:ビルドツール。(3) wee_alloc:小型アロケータ。(4) wasm-opt:バイナリ最適化。(5) web-sys/js-sys:Web API 呼出。
開発フロー
(1) Cargo プロジェクト作成:lib type cdylib。(2) #[wasm_bindgen]でエクスポート関数定義。(3) wasm-pack buildでビルド。(4) npm パッケージとして公開可能。(5) React/Vue から import。
型の橋渡し
(1) プリミティブ型:自動変換。(2) String:UTF-8 で渡す。(3) 配列 (Vec):TypedArray ベース。(4) 構造体:JSON 経由。(5) 関数:closure 対応。TypeScript 上級 もご参考に。
パフォーマンス最適化
(1) release ビルド必須。(2) wasm-opt -O3:さらに最適化。(3) SIMD:並列計算。(4) Web Workersでメインスレッド分離。(5) Shared Memory(SharedArrayBuffer)。Web Vitals 最適化 もご参考に。
実例
(1) 画像処理:フィルタ・リサイズ。(2) 動画エンコード:FFmpeg.wasm。(3) 暗号:argon2 等。(4) 物理シミュレーション:ゲーム。(5) SQLite:sqlite-wasm。
サイズ最適化
(1) wee_alloc:std アロケータ排除。(2) panic=abort:panic コード削除。(3) strip:シンボル削除。(4) lto=true:リンク時最適化。(5) opt-level=z:サイズ優先。数百KB → 数十KB の削減も可能(公開情報をもとに)。
失敗しがちなパターン
(1) 頻繁な JS↔Wasm 呼出:オーバーヘッド大。(2) 巨大なシリアライゼーション。(3) debug ビルド配信:サイズ大。(4) main thread ブロック。(5) 古いブラウザ非対応。対策は、(1)1回の呼出でまとめて処理、(2)TypedArray 直渡し、(3)release+wasm-opt、(4)Web Workers、(5)対応確認、です。