RustとWebAssembly (Wasm) 実践入門
RustとWebAssembly(Wasm)をマスターする:高速ブラウザ演算、wasm-bindgenによるJS相互運用、バンドルサイズ最適化。
第3部:上級システム開発と実践Rust の第4回。WebAssembly(Wasm)は、Webブラウザやエッジ環境(Cloudflare Workersなど)において、ネイティブコードに近い速度で実行できるように設計されたバイナリ命令形式です。
Rustはガベージコレクタ(GC)を持たないため、バイナリサイズが極めて小さく、立ち上がりが高速であることから、WebAssemblyの最適な開発言語として広く認知されています。
graph TD
A["Rustソースコード (.rs)"] --> B["wasm32-unknown-unknown ターゲットへコンパイル"]
B --> C["wasm-bindgen & wasm-pack"]
C --> D["WebAssemblyバイナリ (.wasm)"]
C --> E["JS連携コード & TypeScript型定義 (.d.ts)"]
D & E --> F["Webブラウザ / Cloudflare Workers / Node.js"]
10歳でもわかる説明(ELI5):自転車にジェットエンジンを載せる#
- 通常のJavaScript:街中をスイスイ走れる小回りの利くシティサイクル。DOMの操作や画面の見た目を整えるのに最適です。しかし、重い荷物を運ぶような激しい計算(画像処理、動画編集、暗号計算、3D描画)では限界があります。
- Rust + WebAssembly:自転車に小型ジェットエンジンを取り付けるようなものです。JavaScriptが合図を出すと、超重量級の計算処理をRust Wasmが一瞬で片付け、結果を滑らかに画面へ返します!
1. wasm-bindgen によるプロジェクト構成#
Cargo.toml にライブラリ設定を追加します:
Cargo.toml
[package]
name = "rust-wasm-demo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"] # Wasm用の動的ライブラリを出力
[dependencies]
wasm-bindgen = "0.2"toml2. JavaScriptとRustの双方向連携#
#[wasm_bindgen] 属性を使用することで、JSとRust間のデータ受け渡しが自動生成されます:
src/lib.rs
use wasm_bindgen::prelude::*;
// 1. JavaScriptの alert 関数をRust側へインポート
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
// 2. Rustの関数をJavaScript側へエクスポート
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Rust Wasmからこんにちは、{name} さん!"));
}
// 3. UIスレッドをブロックしない高負荷な計算処理
#[wasm_bindgen]
pub fn calculate_fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => {
let mut a = 0;
let mut b = 1;
for _ in 2..=n {
let c = a + b;
a = b;
b = c;
}
b
}
}
}rust3. wasm-pack によるビルド#
公式のパッケージングツール wasm-pack を使用します:
cargo install wasm-pack
wasm-pack build --target webbash生成される pkg/ フォルダの内容:
rust_wasm_demo_bg.wasm:最適化されたバイナリファイルrust_wasm_demo.js:Wasm初期化用ラッパーrust_wasm_demo.d.ts:TypeScript型定義ファイル
4. フロントエンドでの利用例#
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Rust Wasm デモ</title>
</head>
<body>
<h1>Rust + WebAssembly</h1>
<button id="btn">挨拶する</button>
<script type="module">
import init, { greet, calculate_fibonacci } from './pkg/rust_wasm_demo.js';
async function run() {
// Wasmモジュールのロードと初期化
await init();
document.getElementById('btn').addEventListener('click', () => {
greet('開発者');
console.log('フィボナッチ 50:', calculate_fibonacci(50));
});
}
run();
</script>
</body>
</html>html5. 本番用バイナリサイズの最適化#
Webページの読み込み速度を高めるため、.wasm のファイルサイズを最小化します:
Cargo.tomlの最適化設定:
toml[profile.release] opt-level = "z" # サイズ最優先の最適化 lto = true codegen-units = 1 panic = "abort"wasm-optの活用:不要なコードを除去し、ファイルサイズをさらに20〜30%縮小します。
まとめ#
- RustはGCを持たないため、軽量で起動が速いWebAssemblyバイナリを生成できます。
#[wasm_bindgen]により、JSとRust間の型変換が安全かつ自動的に行われます。wasm-packを使うことで、npmエコシステムやモダンフロントエンドへ簡単に統合できます。