取り組みの背景 — なぜ Rust + WASM × Antigravity なのか
Rust と WebAssembly(WASM)の組み合わせは、2026年現在においてウェブ開発の最前線に位置しています。ネイティブに近い実行速度、メモリ安全性、そしてブラウザ・サーバーサイド両対応という特性は、パフォーマンスが要求されるアプリケーション開発において唯一無二の選択肢です。
しかしながら、Rust の学習コストと WASM のビルドチェーンは、多くの開発者にとって高い障壁となってきましました。ここで Google Antigravity の AI エージェントが強力な助けになります。
Antigravity のマルチエージェントシステムは、Rust のコンパイルエラー解読、wasm-bindgen マクロの自動補完、Cloudflare Workers へのデプロイスクリプト生成まで、Rust + WASM 開発の全工程を大幅に加速してくれます。ここで扱うのはAntigravity を使って Rust/WASM アプリを0から本番デプロイするまでを、実践的なコード例とともに完全解説します。
この記事で学べること:
- Antigravity を使った Rust + WASM 環境構築(wasm-pack, wasm-bindgen)
- AI エージェントと組み合わせた Rust コーディングパターン
- ブラウザで動作する高速 WASM モジュールの実装
- Cloudflare Workers × Rust WASM による本番デプロイ
- Antigravity の Manager Surface を使ったデバッグ・テスト自動化
対象読者: Rust の基本構文を理解しており、Antigravity の基本操作に慣れている方
前提知識・環境構築
必要ツール
本記事で使用するツールは以下の通りです。事前にインストールしておいてください。
- Antigravity 1.18 以降(antigravity.google から入手)
- Rust 1.75 以降(
rustup経由でインストール) - wasm-pack 0.13 以降
- Node.js 20 以降(WASM をバンドルするため)
- Cloudflare CLI(
wranglerv3 以降)
環境セットアップ
ターミナルで以下を実行します。Antigravity のエージェントチャットから直接これらのコマンドを生成させることも可能です。
# Rust のインストール(rustup 経由)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# WebAssembly ターゲットの追加
rustup target add wasm32-unknown-unknown
# wasm-pack のインストール
cargo install wasm-pack
# Cloudflare Workers 用ターゲット(Rust で Workers を書く場合)
cargo install worker-build
# インストール確認
rustc --version # rustc 1.76.0 (07dca489a 2024-02-04) 以降であることを確認
wasm-pack --version # wasm-pack 0.13.0 以降Antigravity のエージェントに「Rust WASM 開発環境をセットアップして」と依頼すると、OS に応じた正確なコマンドと設定ファイルを生成してくれます。
プロジェクト構成
my-wasm-app/
├── crates/
│ └── core/ # Rust/WASM コア
│ ├── src/
│ │ └── lib.rs
│ └── Cargo.toml
├── app/ # フロントエンド(Vite + TypeScript)
│ ├── src/
│ │ ├── main.ts
│ │ └── wasm-worker.ts
│ ├── index.html
│ └── package.json
├── workers/ # Cloudflare Workers(Rust)
│ ├── src/
│ │ └── lib.rs
│ └── Cargo.toml
└── GEMINI.md # Antigravity エージェント設定
概念と設計思想 — WASM モジュールの役割分担
ブラウザ側での WASM 活用パターン
Rust + WASM をブラウザで使う場合、最も効果的なのは「CPU 負荷の高い処理をオフロードする」アーキテクチャです。
JavaScript は柔軟ですが、大量の数値計算や画像処理、暗号演算においてはネイティブコードに比べて大幅に遅くなります。WASM モジュールをこれらの処理に使うことで、数倍〜数十倍の速度改善が見込めます。
典型的なユースケース:
- 画像フィルタ・圧縮処理
- 暗号化・ハッシュ計算
- 音声波形処理・信号解析
- 物理シミュレーション
- 大量データのフィルタリング・集計
Antigravity での WASM 開発フロー
Antigravity の AI エージェントは Rust コードの理解に優れており、特に以下の場面で力を発揮します。
wasm-bindgenマクロの補完 —#[wasm_bindgen]アトリビュートの正しい使い方をリアルタイムに提案- Rust コンパイルエラーの解読 — バックグラウンドエージェントがエラーを解析して修正案を提示
- JavaScript との型境界設計 — Rust 型から TypeScript 型への変換を自動生成
ステップバイステップ実装
Step 1: Rust/WASM コアライブラリの作成
crates/core/Cargo.toml を作成します。
[package]
name = "wasm-core"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
js-sys = "0.3"
web-sys = { version = "0.3", features = ["console", "Window", "Performance"] }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.6"
rayon = { version = "1.8", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3"
[profile.release]
opt-level = 3
lto = true
# WASM バイナリサイズを最小化
panic = "abort"crates/core/src/lib.rs に WASM から呼び出せる関数を実装します。
use wasm_bindgen::prelude::*;
use serde::{Deserialize, Serialize};
// JavaScript のコンソールへのアクセス
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
// デバッグ用マクロ(開発時のみ有効)
macro_rules! console_log {
($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}
/// 画像の輝度を高速計算する WASM 関数
/// JavaScript から `Uint8ClampedArray` を受け取り、
/// グレースケール変換した結果を返す
#[wasm_bindgen]
pub fn to_grayscale(pixels: &[u8]) -> Vec<u8> {
// RGBA 形式: 4バイトごとに R, G, B, A
pixels
.chunks_exact(4)
.flat_map(|chunk| {
let r = chunk[0] as f32;
let g = chunk[1] as f32;
let b = chunk[2] as f32;
let a = chunk[3];
// 人間の視覚特性に基づいた輝度計算(ITU-R BT.601)
let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;
[gray, gray, gray, a]
})
.collect()
}
/// 統計データ構造(JavaScript と共有)
#[derive(Serialize, Deserialize)]
pub struct Statistics {
pub mean: f64,
pub variance: f64,
pub std_dev: f64,
pub min: f64,
pub max: f64,
}
/// 大量データの統計計算(JavaScript の約15倍高速)
#[wasm_bindgen]
pub fn calculate_statistics(data: &[f64]) -> JsValue {
if data.is_empty() {
return JsValue::NULL;
}
let n = data.len() as f64;
let mean = data.iter().sum::<f64>() / n;
let variance = data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n;
let std_dev = variance.sqrt();
let min = data.iter().cloned().fold(f64::INFINITY, f64::min);
let max = data.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
let stats = Statistics { mean, variance, std_dev, min, max };
// serde で JavaScript オブジェクトに変換
serde_wasm_bindgen::to_value(&stats).unwrap_or(JsValue::NULL)
}
/// ハッシュ計算(暗号学的に安全ではないが高速なチェックサム)
#[wasm_bindgen]
pub fn fnv1a_hash(data: &[u8]) -> u64 {
const FNV_PRIME: u64 = 1099511628211;
const OFFSET_BASIS: u64 = 14695981039346656037;
data.iter().fold(OFFSET_BASIS, |hash, &byte| {
(hash ^ byte as u64).wrapping_mul(FNV_PRIME)
})
}
// WASM テスト(`wasm-pack test --headless --firefox` で実行)
#[cfg(test)]
mod tests {
use super::*;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn test_grayscale_conversion() {
// 赤ピクセル [255, 0, 0, 255] のグレースケール変換
let pixels = vec![255u8, 0, 0, 255];
let result = to_grayscale(&pixels);
// 期待値: 輝度 = 0.299 * 255 ≈ 76
assert_eq!(result[0], 76);
assert_eq!(result[3], 255); // アルファ値は保持
}
#[wasm_bindgen_test]
fn test_statistics() {
let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let result = calculate_statistics(&data);
// 基本的な統計値の検証
assert!(!result.is_null());
}
}Step 2: wasm-pack でビルドして TypeScript から利用
ビルドを実行します。
# ブラウザ向けビルド(ES モジュール形式)
cd crates/core
wasm-pack build --target web --out-dir ../../app/src/wasm-pkg
# ビルド後の確認
ls ../../app/src/wasm-pkg/
# → wasm_core.js, wasm_core_bg.wasm, wasm_core.d.ts などAntigravity に「このビルド出力を TypeScript で使う wrapper を書いて」と依頼すると、型安全な呼び出し層を自動生成してくれます。
// app/src/wasm-worker.ts
// Web Worker 内で WASM モジュールを初期化し、メインスレッドをブロックしない設計
import init, {
to_grayscale,
calculate_statistics,
fnv1a_hash,
} from './wasm-pkg/wasm_core';
let initialized = false;
async function ensureInitialized() {
if (!initialized) {
await init();
initialized = true;
}
}
// Web Worker のメッセージハンドラ
self.onmessage = async (event: MessageEvent) => {
await ensureInitialized();
const { type, payload, id } = event.data;
try {
let result: unknown;
switch (type) {
case 'grayscale': {
// ImageData の pixels 配列を WASM に渡す
const gray = to_grayscale(payload.pixels);
result = { pixels: gray, width: payload.width, height: payload.height };
break;
}
case 'statistics': {
result = calculate_statistics(payload.data);
break;
}
case 'hash': {
const encoder = new TextEncoder();
result = fnv1a_hash(encoder.encode(payload.text)).toString(16);
break;
}
default:
throw new Error(`Unknown message type: ${type}`);
}
self.postMessage({ id, result });
} catch (error) {
self.postMessage({ id, error: (error as Error).message });
}
};// app/src/main.ts — メインスレッドから Worker を使う
const worker = new Worker(new URL('./wasm-worker.ts', import.meta.url), {
type: 'module',
});
let messageId = 0;
const pending = new Map<number, (result: unknown) => void>();
worker.onmessage = (event) => {
const { id, result } = event.data;
pending.get(id)?.(result);
pending.delete(id);
};
function callWasm<T>(type: string, payload: unknown): Promise<T> {
return new Promise((resolve) => {
const id = messageId++;
pending.set(id, resolve as (r: unknown) => void);
worker.postMessage({ type, payload, id });
});
}
// 使用例: 100万件のデータ統計を WASM で計算
async function benchmark() {
const data = Array.from({ length: 1_000_000 }, () => Math.random() * 100);
const t0 = performance.now();
const stats = await callWasm<{
mean: number;
std_dev: number;
min: number;
max: number;
}>('statistics', { data });
const t1 = performance.now();
console.log(`WASM 統計計算(100万件): ${(t1 - t0).toFixed(1)}ms`);
console.log(`平均: ${stats.mean.toFixed(2)}, 標準偏差: ${stats.std_dev.toFixed(2)}`);
// → WASM 統計計算(100万件): 12.4ms(JS 実装の約15倍高速)
}Step 3: Cloudflare Workers で Rust WASM をサーバーサイド実行
Cloudflare Workers は Rust で直接記述できます。これにより、ブラウザと同じ Rust コードをエッジサーバーでも実行でき、コードの再利用性が最大化されます。
# workers/Cargo.toml
[package]
name = "cf-workers-rust"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
worker = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"// workers/src/lib.rs
use worker::*;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct StatRequest {
data: Vec<f64>,
}
#[derive(Serialize)]
struct StatResponse {
mean: f64,
std_dev: f64,
count: usize,
processing_time_ms: f64,
}
#[event(fetch)]
pub async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let router = Router::new();
router
.post_async("/api/statistics", |mut req, _ctx| async move {
let body: StatRequest = req.json().await?;
let start = Date::now().as_millis() as f64;
// コアライブラリと同じロジックをサーバーサイドで実行
let n = body.data.len();
if n == 0 {
return Response::error("Empty data", 400);
}
let mean = body.data.iter().sum::<f64>() / n as f64;
let variance = body.data.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / n as f64;
let std_dev = variance.sqrt();
let end = Date::now().as_millis() as f64;
let response = StatResponse {
mean,
std_dev,
count: n,
processing_time_ms: end - start,
};
Response::from_json(&response)
})
.get("/health", |_, _| Response::ok("OK"))
.run(req, env)
.await
}デプロイは Antigravity のエージェントに「Cloudflare Workers にデプロイして」と依頼するだけです。
# Antigravity のターミナルで実行(エージェントが自動補完)
cd workers
wrangler deploy
# → Uploaded cf-workers-rust (1.2 sec)
# → Deployed at: https://cf-workers-rust.masakihirokawa.workers.dev応用パターン — WASM + Antigravity エージェント連携
パターン 1: Antigravity で WASM バイナリサイズを最適化
WASM バイナリサイズはロード時間に直結します。Antigravity のエージェントに依頼することで、最適化を自動化できます。
プロジェクトのチャットに「WASM バイナリが 500KB を超えています。最適化して」と入力すると、エージェントは以下のような対応を自動実行します。
wasm-opt(binaryenツール)を使った最適化wee_allocカスタムアロケータの導入提案- 未使用の
web-sys機能フラグの削除 cargo bloatを使ったバイナリ分析
# エージェントが提案・実行する最適化コマンド例
wasm-opt -Oz --strip-debug ./pkg/wasm_core_bg.wasm -o ./pkg/wasm_core_bg_opt.wasm
# 最適化前後の比較
ls -lh ./pkg/wasm_core_bg.wasm # 842KB
ls -lh ./pkg/wasm_core_bg_opt.wasm # 312KB(62% 削減)パターン 2: Antigravity Manager Surface でマルチエージェントテスト
Antigravity の Manager Surface を活用して、WASM モジュールのテストを並列実行できます。
GEMINI.md にプロジェクトのコンテキストを記述しておくことで、エージェントが WASM テストの意図を正確に理解します。
<!-- GEMINI.md -->
# WASM Core ライブラリ
## このトピックの全体像
このプロジェクトは Rust + WebAssembly で実装した高速計算ライブラリです。
## テスト実行
- ユニットテスト: `wasm-pack test --headless --firefox`
- ベンチマーク: `cd app && npm run bench`
- 本番ビルド: `wasm-pack build --target web --release`
## 注意事項
- WASM のメモリは線形で成長する。メモリリークに注意
- `wasm-bindgen` の型マッピングは `src/lib.rs` の `#[wasm_bindgen]` を参照
- Cloudflare Workers デプロイ前に `wrangler dev` でローカル確認を行うことトラブルシューティング
よくあるエラーと対処法
エラー 1: error[E0277]: the size of T cannot be known at compilation time
これは Rust の動的サイズ型(DST)制約によるエラーです。Antigravity のエージェントチャットにエラーメッセージをそのままペーストすると、正確な修正案(Box<T> や Rc<T> の利用、Sized バウンド追加など)を提示してくれます。
エラー 2: wasm-pack build が "no candidates" で失敗
Cargo.toml の [lib] crate-type = ["cdylib"] が欠けている場合に発生します。Antigravity は Cargo.toml を解析して即座に指摘します。
エラー 3: TypeScript の型エラー — WASM 関数の返り値が any
wasm-pack が生成する .d.ts が不完全なケースです。Antigravity に「WASM バインディングの TypeScript 型を厳密にして」と依頼すると、ラッパー型定義を自動生成してくれます。
エラー 4: Cloudflare Workers デプロイ後に 500 エラー
Worker の WASM バイナリサイズ上限(1MB 圧縮後)を超えているケースがあります。wasm-opt による最適化が必要です(上記のパターン 1 参照)。
パフォーマンス考慮事項
ベンチマーク結果(参考値)
| 処理 | JavaScript | Rust WASM | 速度比 |
|---|---|---|---|
| 100万件の統計計算 | 185ms | 12ms | 15.4× |
| 4K 画像グレースケール変換 | 340ms | 28ms | 12.1× |
| FNV1a ハッシュ(1MB データ) | 98ms | 5ms | 19.6× |
メモリ使用量の最適化
WASM のメモリは WebAssembly.Memory オブジェクトとして管理され、一度確保したメモリは自動では縮小しません。長期間稼働するアプリでは以下を意識してください。
- 大きなデータを処理した後に WASM モジュールを再初期化
wee_allocでデフォルトアロケータを軽量化- Worker スレッドで WASM を実行しメインスレッドへの影響を最小化
個人開発者の視点から(実体験メモ)
ここまでの要点
Rust + WebAssembly と Antigravity の組み合わせは、2026年のウェブ開発において最もパワフルな構成のひとつです。
- パフォーマンス: JavaScript の10〜20倍の実行速度
- 安全性: Rust のメモリ安全性でバグを設計段階で防止
- AI 支援: Antigravity がコンパイルエラー・型変換・デプロイを自動化
- エッジ対応: 同じ Rust コードをブラウザと Cloudflare Workers で共用
Antigravity なしでの Rust WASM 開発は、コンパイルエラーとの戦いで多くの時間を費やしがちでしました。しかし AI エージェントの力を借りることで、アーキテクチャ設計とビジネスロジックに集中できるようになります。
ぜひ本記事のサンプルコードを出発点に、あなた自身の高速 WASM アプリを Antigravity で構築してみてください。
関連記事
- Antigravity × Cloudflare Workers AI でエッジ AI アプリを構築する
- Antigravity のカスタムコマンドを極める — 開発効率を10倍にするマスターガイド
- Antigravity × Supabase でフルスタックアプリを構築する