WebAssembly入門2026 — Webの限界を超える技術


WebAssembly入門2026 — Webの限界を超える技術

WebAssembly(Wasm)は、Webブラウザ上でネイティブに近い速度でコードを実行できる革新的な技術です。JavaScriptでは実現困難だった高速な画像処理、ゲーム、暗号化処理などを可能にし、Webアプリケーションの可能性を大きく広げています。この記事では、WebAssemblyの基礎から実践的な活用方法まで、2026年の最新情報とともに徹底解説します。

WebAssemblyとは

WebAssembly(略称: Wasm)は、スタックベースの仮想マシンのためのバイナリ命令フォーマットです。2019年にW3Cの正式な勧告となり、現在ではすべての主要ブラウザでサポートされています。

WebAssemblyの特徴

ネイティブに近い実行速度 Wasmは低レベルのバイナリフォーマットであり、JITコンパイラを経由せず直接実行されるため、JavaScriptよりも高速です。計算集約的なタスクでは、JavaScriptの10〜100倍の速度が得られることもあります。

言語非依存 C、C++、Rust、Go、AssemblyScriptなど、さまざまな言語からWasmにコンパイルできます。既存のC/C++ライブラリをWebで再利用することも可能です。

安全なサンドボックス実行 Wasmはブラウザのサンドボックス内で実行され、メモリ安全性が保証されています。ネイティブコードのパフォーマンスを得ながら、セキュリティも確保できます。

小さいバイナリサイズ 効率的なバイナリフォーマットにより、ファイルサイズが小さく、ネットワーク転送が高速です。

JavaScriptとの相互運用 WasmはJavaScriptと共存し、相互に呼び出すことができます。JavaScriptでUIを構築し、重い処理だけWasmに任せる、といった使い方が可能です。

なぜWebAssemblyが必要か

JavaScriptは非常に優れた言語ですが、計算集約的なタスクには向いていません。

  • 画像・動画処理: フィルタ適用、リサイズ、エンコーディング
  • ゲーム: 物理演算、3Dレンダリング
  • 科学計算: シミュレーション、データ分析
  • 暗号化: ハッシュ計算、暗号化/復号化
  • コンパイラ: エディタ内でのコードコンパイル

これらをJavaScriptで実装すると、パフォーマンスがボトルネックになります。Wasmはこの問題を解決します。

WebAssemblyの基本構造

Wasmモジュールの構成要素

Wasmモジュールは以下の要素で構成されます。

メモリ 線形メモリと呼ばれる連続したバイト配列。JavaScriptとWasm間でデータをやり取りする際に使用します。

テーブル 関数参照を格納するための配列。動的な関数呼び出しに使用されます。

関数 Wasmの実行単位。エクスポートされた関数はJavaScriptから呼び出せます。

グローバル変数 モジュール内で共有される変数。

テキストフォーマット(WAT)

Wasmはバイナリですが、人間が読めるテキストフォーマット(WAT: WebAssembly Text Format)も存在します。

(module
  (func $add (param $a i32) (param $b i32) (result i32)
    local.get $a
    local.get $b
    i32.add)
  (export "add" (func $add))
)

このWATは、2つの整数を受け取って加算する関数を定義し、JavaScriptからアクセスできるようにエクスポートしています。

JavaScriptからのロード

ブラウザでWasmを読み込むには、WebAssembly APIを使用します。

// Fetch and instantiate
const response = await fetch('module.wasm')
const buffer = await response.arrayBuffer()
const { instance } = await WebAssembly.instantiate(buffer)

// Call exported function
const result = instance.exports.add(5, 3)
console.log(result) // 8

Rust → Wasm のビルド

Rustは最もポピュラーなWasmターゲット言語の一つです。メモリ安全性とゼロコスト抽象化により、安全かつ高速なWasmモジュールを作成できます。

環境構築

1. Rustのインストール

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

2. wasm-packのインストール wasm-packは、RustコードをWasmにビルドし、npm packageとして公開するためのツールです。

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

3. プロジェクト作成

cargo new --lib hello-wasm
cd hello-wasm

Cargo.tomlの設定

[package]
name = "hello-wasm"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

wasm-bindgenは、RustとJavaScript間の相互運用を簡単にするライブラリです。

Rustコードの作成

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n - 1) + fibonacci(n - 2),
    }
}

#[wasm_bindgen]
pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

#[wasm_bindgen]マクロにより、関数がJavaScriptから呼び出せるようになります。

ビルド

wasm-pack build --target web

これにより、pkgディレクトリに以下が生成されます。

  • hello_wasm_bg.wasm: Wasmバイナリ
  • hello_wasm.js: JavaScriptバインディング
  • hello_wasm.d.ts: TypeScript型定義

JavaScriptから使用

import init, { fibonacci, greet } from './pkg/hello_wasm.js'

await init() // Wasmモジュールを初期化

console.log(fibonacci(10)) // 55
console.log(greet('World')) // "Hello, World!"

実践例:画像処理

Rustで画像のグレースケール変換を実装してみましょう。

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn grayscale(data: &mut [u8]) {
    for chunk in data.chunks_mut(4) {
        let r = chunk[0] as f32;
        let g = chunk[1] as f32;
        let b = chunk[2] as f32;

        // グレースケール値を計算
        let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;

        chunk[0] = gray;
        chunk[1] = gray;
        chunk[2] = gray;
        // chunk[3]はアルファ値なので変更しない
    }
}

JavaScript側:

import init, { grayscale } from './pkg/image_processor.js'

await init()

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)

// Wasmで画像処理
grayscale(imageData.data)

// 結果を描画
ctx.putImageData(imageData, 0, 0)

このコードはJavaScriptで同じ処理をするよりも5〜10倍高速です。

C++ → Wasm のビルド

既存のC++ライブラリをWebで使いたい場合、Emscriptenを使ってWasmにコンパイルできます。

Emscriptenのセットアップ

# Emscriptenのダウンロード
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk

# 最新版のインストール
./emsdk install latest
./emsdk activate latest

# 環境変数の設定
source ./emsdk_env.sh

C++コードの作成

// hello.cpp
#include <emscripten/bind.h>
#include <string>

int add(int a, int b) {
    return a + b;
}

std::string greet(std::string name) {
    return "Hello, " + name + "!";
}

EMSCRIPTEN_BINDINGS(my_module) {
    emscripten::function("add", &add);
    emscripten::function("greet", &greet);
}

ビルド

emcc hello.cpp -o hello.js \
  -lembind \
  -s WASM=1 \
  -s MODULARIZE=1 \
  -s EXPORT_ES6=1

JavaScriptから使用

import Module from './hello.js'

const module = await Module()
console.log(module.add(5, 3)) // 8
console.log(module.greet('Wasm')) // "Hello, Wasm!"

実践例:暗号化ライブラリ

C++の暗号化ライブラリをWasmで使う例:

#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <vector>
#include <cstring>

// シンプルなXOR暗号化
std::vector<uint8_t> xor_encrypt(const std::vector<uint8_t>& data,
                                  const std::vector<uint8_t>& key) {
    std::vector<uint8_t> result(data.size());
    for (size_t i = 0; i < data.size(); ++i) {
        result[i] = data[i] ^ key[i % key.size()];
    }
    return result;
}

EMSCRIPTEN_BINDINGS(crypto_module) {
    emscripten::function("xorEncrypt", &xor_encrypt);
    emscripten::register_vector<uint8_t>("VectorUint8");
}

JavaScript側:

import Module from './crypto.js'

const module = await Module()
const data = new Uint8Array([72, 101, 108, 108, 111]) // "Hello"
const key = new Uint8Array([42])

const encrypted = module.xorEncrypt(data, key)
console.log(encrypted)

JavaScriptとの連携

WasmとJavaScriptは密接に連携できます。それぞれの得意分野を活かした設計が重要です。

データの受け渡し

プリミティブ型 整数、浮動小数点数はそのまま受け渡しできます。

#[wasm_bindgen]
pub fn calculate(x: f64, y: f64) -> f64 {
    x * y + 10.0
}

文字列 wasm-bindgenが自動的に変換します。

#[wasm_bindgen]
pub fn process_text(text: &str) -> String {
    text.to_uppercase()
}

配列・バッファ 大きなデータは共有メモリを使って効率的にやり取りします。

#[wasm_bindgen]
pub fn process_array(data: &mut [f64]) {
    for item in data.iter_mut() {
        *item = item.sqrt();
    }
}

複雑なオブジェクト JSONやserde経由でシリアライズします。

use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
pub struct User {
    name: String,
    age: u32,
}

#[wasm_bindgen]
pub fn create_user(json: &str) -> JsValue {
    let user: User = serde_json::from_str(json).unwrap();
    // ... process user
    serde_wasm_bindgen::to_value(&user).unwrap()
}

パフォーマンス最適化

メモリコピーを減らす 大きなデータは共有メモリを使い、コピーを避けます。

#[wasm_bindgen]
pub fn get_memory_ptr() -> *const u8 {
    // Wasmのメモリへのポインタを返す
    // JavaScriptから直接アクセス可能
}

関数呼び出しのオーバーヘッド 頻繁に呼び出される小さな関数は、まとめて一度に処理します。

// 悪い例:ループの中でJS呼び出し
for i in 0..1000 {
    call_js_function(i);
}

// 良い例:まとめて処理
#[wasm_bindgen]
pub fn process_batch(count: usize) {
    // Wasm内で完結
}

TypeScript統合

wasm-packはTypeScript型定義も自動生成します。

import init, { fibonacci, greet } from './pkg/hello_wasm'

await init()

const result: number = fibonacci(10)
const message: string = greet('TypeScript')

型安全性が確保され、IDEの補完も効きます。

ユースケース

1. 画像処理

Photopea(https://www.photopea.com/)のような高度な画像エディタがWasmで実装されています。

実装例:画像フィルタ

#[wasm_bindgen]
pub fn apply_blur(data: &mut [u8], width: usize, height: usize, radius: usize) {
    // ガウシアンブラーの実装
    // JavaScriptで実装すると遅いが、Wasmなら高速
}

2. ゲーム

UnityやUnrealEngineはWasmエクスポートをサポートしています。

実装例:物理演算

#[wasm_bindgen]
pub struct PhysicsEngine {
    bodies: Vec<Body>,
}

#[wasm_bindgen]
impl PhysicsEngine {
    pub fn step(&mut self, delta_time: f64) {
        // 物理シミュレーション
        for body in &mut self.bodies {
            body.update(delta_time);
        }
    }
}

3. 暗号化

bcrypt、argon2などの計算コストの高い暗号化をWasmで実行します。

use argon2::{self, Config};

#[wasm_bindgen]
pub fn hash_password(password: &str) -> String {
    let salt = b"randomsalt";
    let config = Config::default();
    argon2::hash_encoded(password.as_bytes(), salt, &config).unwrap()
}

4. コンパイラ・インタプリタ

Monaco Editor(VS Codeのエディタ部分)はTypeScriptコンパイラをWasmで実行しています。

5. データ圧縮

use flate2::write::GzEncoder;
use flate2::Compression;
use std::io::Write;

#[wasm_bindgen]
pub fn compress(data: &[u8]) -> Vec<u8> {
    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
    encoder.write_all(data).unwrap();
    encoder.finish().unwrap()
}

WASI(WebAssembly System Interface)

WASIは、Wasmをブラウザ外(サーバーサイド、CLI、IoTなど)で実行するための標準インターフェースです。

WASIとは

WASIは、Wasmモジュールがファイルシステム、ネットワーク、環境変数などのシステムリソースにアクセスするための標準APIです。「一度書けばどこでも実行できる」ユニバーサルバイナリを実現します。

WASIの利点

ポータビリティ Linux、Windows、macOS、さらにはIoTデバイスでも同じWasmバイナリが動作します。

セキュリティ capability-basedセキュリティモデルにより、明示的に許可されたリソースにしかアクセスできません。

軽量 コンテナよりもはるかに軽量で、起動が高速です。

WASIの実行環境

Wasmtime 最も人気のあるWASIランタイム。

# インストール
curl https://wasmtime.dev/install.sh -sSf | bash

# 実行
wasmtime run program.wasm

Wasmer Wasmtimeと並ぶ主要ランタイム。

# インストール
curl https://get.wasmer.io -sSf | sh

# 実行
wasmer run program.wasm

RustでWASIプログラムを作成

use std::env;
use std::fs;

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        return;
    }

    let contents = fs::read_to_string(&args[1])
        .expect("Failed to read file");

    println!("File contents:\n{}", contents);
}

ビルド:

rustup target add wasm32-wasi
cargo build --target wasm32-wasi --release

実行:

wasmtime run target/wasm32-wasi/release/myprogram.wasm -- test.txt

WASIのユースケース

サーバーレス関数 Cloudflare WorkersやFastlyのCompute@Edgeは、WASIベースのサーバーレスプラットフォームです。

プラグインシステム 安全にサードパーティコードを実行できます。

CLIツール クロスプラットフォームのCLIツールをWasmで配布できます。

まとめ

WebAssemblyは、Webアプリケーションの可能性を大きく広げる技術です。JavaScriptでは実現困難だった高速な処理を可能にし、既存のC/C++/Rustライブラリを活用できます。

WebAssemblyを使うべきケース

  • 計算集約的な処理(画像処理、暗号化、シミュレーション)
  • 既存のネイティブライブラリの再利用
  • ゲームや3Dアプリケーション
  • 大量のデータ処理

WebAssemblyを使わないケース

  • 単純なDOM操作
  • 小規模なビジネスロジック
  • ネットワークI/O中心の処理

2026年現在、WebAssemblyは成熟した技術として、多くのプロダクションアプリケーションで使用されています。Figma、Google Earth、AutoCADなどの有名サービスもWasmを活用しています。

Rustの台頭により、Wasmの開発体験は大きく向上しました。wasm-packやwasm-bindgenのような優れたツールにより、初心者でも簡単にWasmアプリケーションを構築できます。

またWASIにより、Wasmはブラウザを超えてサーバーサイド、エッジコンピューティング、IoTなど、さまざまな環境で利用できるようになっています。

WebAssemblyは、Webの未来を形作る重要な技術です。ぜひ実際に試して、その可能性を体験してみてください。