Contents
必要ツールと環境設定
このセクションでは、Rust と WebAssembly の開発を始めるために最低限必要なツールと、VSCode で快適にコーディングできるようにする設定方法を紹介します。すべて公式ドキュメントが提供しているインストーラで取得でき、プラットフォーム間の挙動差異を意識せずに作業できます。
1. 基本ツールのインストール
以下のツールは 必須 です。すべて「最新安定版」をインストールすることを推奨します(バージョン番号は公式サイトをご確認ください)。
| ツール | 主な用途 |
|---|---|
rustup / cargo |
Rust コンパイラとビルドシステム |
node.js + npm (または yarn) |
フロントエンドの依存管理・開発サーバー |
wasm-pack |
Rust から Wasm パッケージを生成 |
wasm-bindgen-cli |
Wasm と JavaScript の橋渡しコード生成 |
インストールコマンド例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 1. rustup(Rust ツールチェーン)インストール curl https://sh.rustup.rs -sSf | sh -s -- -y source $HOME/.cargo/env # 2. wasm32-unknown-unknown ターゲットを追加 rustup target add wasm32-unknown-unknown # 3. Node.js と npm(nvm 経由でインストール推奨) curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source ~/.bashrc nvm install --lts # LTS バージョンを取得 # 4. Yarn が必要な場合(任意) npm install -g yarn # 5. wasm-pack のインストール(公式スクリプト利用) curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh # 6. wasm-bindgen-cli のインストール cargo install -f wasm-bindgen-cli |
ポイント:
cargo installはローカルの~/.cargo/binにバイナリを配置します。パスが通っていない場合は、シェル設定に追記してください。
2. VSCode の推奨拡張と Cargo 設定
VSCode で Rust 開発を快適に行うための拡張機能と、cargo が自動的に Wasm ターゲットを使用するように設定します。ここでは 導入手順 と 設定ファイル例 を示します。
推奨拡張
| 拡張名 | 目的 |
|---|---|
| Rust Analyzer | 高速インテリセンスとオンザフライ型チェック |
| Better TOML | Cargo.toml のシンタックスハイライト |
| CodeLLDB | Wasm デバッグ用ブレークポイントサポート |
| ESLint + Prettier (JS/TS) | フロントエンドコードの品質維持 |
Cargo 設定ファイル
プロジェクトルート(または $HOME/.cargo/config.toml)に次の内容を書き込みます。これにより cargo build --release が自動的に Wasm 用バイナリを生成します。
|
1 2 3 4 |
# .cargo/config.toml [build] target = "wasm32-unknown-unknown" |
Rust プロジェクトの作成と基本コード
この章では、Rust のライブラリプロジェクトを作成し、#[wasm_bindgen] アトリビュートでエクスポートできる最小構成を示します。画像処理を例に取ることで、実務的に有用な API デザインの感覚も掴めます。
1. ライブラリプロジェクトの生成
cargo new --lib コマンドで作成したライブラリは、Wasm 用コードだけを格納できるためフロントエンド側からシンプルに呼び出すことができます。
|
1 2 3 |
cargo new --lib image_filter cd image_filter |
Cargo.toml の設定例
|
1 2 3 4 5 6 7 8 9 10 11 |
[package] name = "image_filter" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] # Wasm 出力に必須 [dependencies] wasm-bindgen = { version = "*", features = ["serde-serialize"] } |
注意:
wasm-bindgenのバージョンは*(最新)で構いません。公式ドキュメントの「Getting Started」ページに常に最新版が掲載されています。
2. エクスポート関数の実装
以下は、文字列を返す簡易例と、画像データ(RGBA の Uint8Array)をグレースケール化するサンプルです。重要なのは #[wasm_bindgen] アトリビュートが正しく記述されている点です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
use wasm_bindgen::prelude::*; /// JavaScript から呼び出せる文字列関数 #[wasm_bindgen] pub fn greet(name: &str) -> String { format!("Hello, {}!", name) } /// Uint8Array(RGBA)を受け取り、グレースケール変換した結果を返す #[wasm_bindgen] pub fn apply_grayscale(data: &[u8]) -> Vec<u8> { // data は RGBA と仮定し、各ピクセルごとに輝度計算を行う let mut out = data.to_vec(); for i in (0..out.len()).step_by(4) { let r = out[i] as f32; let g = out[i + 1] as f32; let b = out[i + 2] as f32; // ITU-R BT.601 の輝度係数 let gray = (0.299 * r + 0.587 * g + 0.114 * b).round() as u8; out[i] = gray; out[i + 1] = gray; out[i + 2] = gray; } out } |
ポイント:
apply_grayscaleは&[u8](JavaScript のUint8Array)を受け取り、加工後はVec<u8>として返すだけです。追加のメモリコピーやポインタ操作は不要で、安全にデータをやり取りできます。
Wasm のビルドと生成物の配置
このセクションでは、wasm-pack を使って Rust ライブラリをビルドし、Vite プロジェクトへ組み込むまでの流れを解説します。ビルドコマンド と ファイル配置手順 に焦点を当てます。
1. wasm-pack ビルド
wasm-pack は Cargo のラッパーで、Wasm と JavaScript ラッパーコードを自動生成します。Vite が内部的に Rollup/ESBuild を利用しているので、bundler ターゲットが最も相性が良いです。
|
1 2 3 |
# プロジェクトルートで実行(--release で最適化ビルド) wasm-pack build --target bundler --out-dir pkg --release |
生成される主なファイルは次の通りです。
| ファイル | 内容 |
|---|---|
pkg/image_filter.js |
ES モジュール形式のラッパー |
pkg/image_filter_bg.wasm |
実体 Wasm バイナリ |
pkg/image_filter.d.ts |
TypeScript 用型定義(自動生成) |
2. Vite プロジェクトへの配置
Vite のデフォルト設定では src/ 以下のファイルが自動的にビルド対象になるため、pkg/ ディレクトリを プロジェクトの src/pkg/ にコピーすれば追加設定は不要です。
|
1 2 3 |
# 例: Vite プロジェクトが sibling ディレクトリにあるケース cp -r pkg ../my-vite-app/src/pkg |
React 側からは次のようにインポートします(TypeScript)。
|
1 2 3 4 5 6 7 |
// src/pkg/image_filter.d.ts が自動生成されているので型補完が効く import init, { greet, apply_grayscale } from "./pkg/image_filter.js"; export async function loadWasm() { await init(); // Wasm モジュールのロードとインスタンス化 } |
Vite + React + TypeScript への統合
この章では、Vite の設定変更点と実際に React コンポーネントから Wasm 関数を呼び出すサンプルコードを示します。開発環境の構築 と UI ロジック に分けて解説します。
1. Vite の Wasm 対応設定
Vite が .wasm ファイルをアセットとして扱えるように assetsInclude を追加し、デバッグ時に source map を有効化します。これだけで開発サーバー上で Wasm が正しく配信されます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// vite.config.js import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()], // .wasm をビルド対象に含める設定 assetsInclude: ["**/*.wasm"], build: { sourcemap: true, // デバッグ用 source map を生成 }, }); |
2. React コンポーネントでの利用例
以下は、画像ファイルを選択すると Rust 側でグレースケール変換し、結果を画面に表示するシンプルなコンポーネントです。useEffect で Wasm の非同期初期化を行い、ボタン操作時に apply_grayscale を呼び出します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
// src/App.tsx import React, { useEffect, useState } from "react"; import init, { greet, apply_grayscale } from "./pkg/image_filter.js"; const App: React.FC = () => { const [ready, setReady] = useState(false); const [message, setMessage] = useState(""); const [srcUrl, setSrcUrl] = useState<string | null>(null); const [outUrl, setOutUrl] = useState<string | null>(null); // Wasm のロード(1 回だけ実行) useEffect(() => { init().then(() => { const msg = greet("React"); console.log(msg); setMessage(msg); setReady(true); }); }, []); // ファイル選択時のハンドラ const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { if (!e.target.files?.[0]) return; const file = e.target.files[0]; const buffer = await file.arrayBuffer(); const input = new Uint8Array(buffer); // Rust 側でグレースケール変換 const result = apply_grayscale(input); const blob = new Blob([result], { type: "image/png" }); setSrcUrl(URL.createObjectURL(file)); setOutUrl(URL.createObjectURL(blob)); }; return ( <div style={{ padding: "2rem", fontFamily: "sans-serif" }}> <h1>Rust + Wasm で画像をグレースケール変換</h1> <p>{message}</p> {!ready && <p>Wasm をロード中…</p>} <input type="file" accept="image/*" onChange={handleChange} /> {srcUrl && ( <div style={{ display: "flex", gap: "1rem", marginTop: "1rem" }}> <figure> <figcaption>元画像</figcaption> <img src={srcUrl} alt="original" width={300} /> </figure> {outUrl && ( <figure> <figcaption>加工後(グレースケール)</figcaption> <img src={outUrl} alt="grayscale" width={300} /> </figure> )} </div> )} </div> ); }; export default App; |
このコンポーネントは npm run dev(または yarn dev)で起動した Vite 開発サーバー上ですぐに動作し、ブラウザの DevTools から Wasm のソースマップを使ってデバッグできます。
デバッグ・最適化・ベストプラクティス
実務プロジェクトでは、開発効率と本番パフォーマンスの両立が求められます。ここでは、自動リビルド, サイズ圧縮, セキュリティ強化 の3点に絞って具体策を示します。
1. ソースコード変更時の自動リビルド
cargo-watch を利用すれば Rust ファイルが更新されるたびに wasm-pack が再実行され、Vite のホットリロードと連携できます。
|
1 2 3 4 5 6 |
# cargo-watch のインストール(未導入の場合) cargo install cargo-watch # プロジェクトルートで監視開始 cargo watch -i "pkg/*" -s "wasm-pack build --target bundler" |
source map が有効な状態でビルドすれば、Chrome の DevTools → Sources タブに .rs ファイルが表示され、debugger; ステートメントやブレークポイントでステップ実行できます。
2. Wasm バイナリのサイズ削減
バイナリサイズはロード時間に直結します。公式が提供する binaryen の wasm-opt ツールを使うと、最適化レベル -Oz(サイズ優先)で数十パーセントの縮小が期待できます。
|
1 2 3 4 5 6 |
# binaryen のインストール(npm 経由) npm i -g binaryen # 最適化実行例 wasm-opt -Oz pkg/image_filter_bg.wasm -o pkg/image_filter_bg_opt.wasm |
最適化後のファイル名を index.html や Vite のエントリで差し替えるだけで、本番環境に反映できます。
3. CSP と Subresource Integrity (SRI) による安全性向上
WebAssembly はバイナリコードなので、配信時の改ざん防止策が重要です。Content‑Security‑Policy ヘッダーでスクリプト・Wasm のロード元を限定し、integrity 属性でハッシュ検証を行います。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!-- index.html のヘッドに追加 --> <meta http-equiv="Content-Security-Policy" content=" default-src 'self'; script-src 'self' 'sha384-XXXXX...'; style-src 'self'; object-src 'none'; base-uri 'self'; "> <!-- Wasm ラッパー(ESモジュール)のインテグリティ例 --> <script type="module" src="/src/main.tsx" integrity="sha384-3vLk1..."></script> |
integrity のハッシュは次のコマンドで生成できます。
|
1 2 |
openssl dgst -sha384 -binary path/to/file.js | openssl base64 -A |
実務で役立つユースケース例
Rust+Wasm が特に威力を発揮するシーンをいくつか紹介します。画像処理, データ可視化, 暗号計算 の3領域は、フロントエンドの CPU バウンドなタスクで顕著な速度向上が報告されています(公式ブログや技術記事に実測値あり)。
| ユースケース | 主な処理内容 | 期待できる効果 |
|---|---|---|
| 画像フィルタ / エッジ検出 | ピクセル単位の演算・カーネル適用 | リアルタイムプレビューが可能、JS より 3〜5 倍高速化 |
| 大規模データ可視化(WebGL 連携) | 数十万点の座標変換・色付け | GC 負荷低減でフレームレート向上、インタラクティブ性が改善 |
| 暗号・ハッシュ計算 | SHA‑256 / Blake3 実装 | WebCrypto が利用できない環境でも高速に検証可能 |
これらのケースでは、Rust の所有権システムと最適化コンパイラが「安全かつ高速」なコードを提供し、フロントエンド開発者は 「ボトルネックが見えたら Rust+Wasm に置き換える」 という判断基準を持てます。
まとめ
| 項目 | 内容 |
|---|---|
| ツールチェーン | rustup, node.js/npm (または yarn), wasm-pack, wasm-bindgen-cli を公式手順でインストールし、VSCode 拡張と .cargo/config.toml で Wasm ターゲットを固定 |
| Rust プロジェクト | cargo new --lib → crate-type = ["cdylib"] → #[wasm_bindgen] で関数・構造体をエクスポート |
| ビルド & 配置 | wasm-pack build --target bundler --out-dir pkg --release の出力を Vite の src/pkg/ にコピーし、TypeScript から import init, { … } from "./pkg/your_pkg.js" と使用 |
| Vite + React 統合 | vite.config.js に assetsInclude: ["**/*.wasm"] と sourcemap:true を追加。React の useEffect で Wasm 初期化、画像データは Uint8Array → Rust 関数 → Blob URL で表示 |
| デバッグ・最適化 | cargo watch + wasm-pack で自動リビルド、wasm-opt -Oz でサイズ圧縮、CSP/SRI による配信安全性確保 |
| 実務ユースケース | 画像処理・大規模データ可視化・暗号計算など、CPU バウンドタスクで 3〜5 倍の速度向上が期待できる |
この手順を踏めば、最新ツールチェーンとベストプラクティスに沿った Rust+WebAssembly アプリ を Vite + React + TypeScript 環境へシームレスに統合できます。ぜひローカルでビルドし、ブラウザ上で高速な Rust コードを体感してください。