🎉

React + TypeScript + Vite で Wasmを触ってみるメモ

に公開

環境

  • ubuntu 22.04 LTS
  • bun 1.0.14
  • vite 5.0.0
  • typescript 5.2.2
  • react 18.2.0
  • wabt 1.0.32

環境構築

bunのインストール。

curl -fsSL https://bun.sh/install | bash

が、以下のコマンドで環境作成が途中までで止まってしまう...。

bun create vite vite-react-wasm-example

もしかして、と思ってnpmとNode.jsをインストール。(こちらを参考にしています)

sudo apt install -y nodejs npm
sudo npm i -g n
sudo n stable
sudo apt purge -y nodejs npm
sudo autoremove -y

もう一度以下を実行したら、最後まで完遂しました。うーん?

bun create vite vite-react-wasm-example

初期インストールと、wabtの追加

cd vite-react-wasm-example
bun i
bun i -D wabt

一旦起動してみる。

bun dev

実装

初期画面のカウンターをwasmで計算させてみる。

src/increment.wat
(module
  (func (export "increment") (param $value i32) (result i32)
    (i32.add (local.get $value) (i32.const 1))
  )
)
src/App.tsx
import { useState, useEffect, useRef } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import './App.css';

type Increment = (value: number) => number;

function App() {
  const [count, setCount] = useState<number>(0);
  const wasmFunctions = useRef<{ increment?: Increment }>({});

  useEffect(() => {
    const loadWasm = async () => {
      try {
        const module = await WebAssembly.instantiateStreaming(fetch('/increment.wasm'));
        wasmFunctions.current = {
          increment: module.instance.exports.increment as Increment
        };
      } catch (error) {
        console.error('Error loading WebAssembly module:', error);
      }
    };

    loadWasm();
  }, []);

  const handleButtonClick = () => {
    const newCount = wasmFunctions.current.increment?.(count) ?? 0;
    setCount(newCount);
  };

  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={handleButtonClick}>
          count is {count}
        </button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">
        Click on the Vite and React logos to learn more
      </p>
    </>
  );
};

export default App;

WATをコンパイルしてpublicに置く。

bunx wat2wasm src/increment.wat -o public/increment.wasm

ホットリロードで起動。

bun dev

とりあえず動きました。

Discussion