👻

Rust + Web Worker(TypeScript + Vite)を試してみたメモ

2024/07/19に公開

概要

前回は「RustとWebAssemblyによるゲーム開発」の写経をした。
今回はRustとWeb Workerをつなげてみる。

ソースコード

ソースコード

package.json
{
  "name": "@kartagraph/worker",
  "type": "module",
  "scripts": {
    "build": "rimraf dist pkg &&  wasm-pack build --target web && tsc",
    "watch-build": "cargo watch -w rust -s \"npm run build\""
  },
  "devDependencies": {
    "rimraf": "^6.0.1",
  }
}

Cargo.toml

lib.rs
use gloo_utils::format::JsValueSerdeExt;
use serde::{Deserialize, Serialize};
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
  #[wasm_bindgen(js_namespace = console)]
  fn log(s: &str);
}

#[wasm_bindgen]
pub fn console_log(message: &str) {
  log(message)
}

#[derive(Serialize, Deserialize)]
pub struct Monster {
  name: String,
  value: String,
}

#[wasm_bindgen]
pub fn return_new_monster(val: &JsValue) -> JsValue {
  let mut m: Monster = val.into_serde().unwrap();
  m.value = "new value!!!".to_string();
  JsValue::from_serde(&m).unwrap()
}

#[wasm_bindgen]
pub fn return_js_value() -> JsValue {
  JsValue::NULL
}
sample.worker.ts
import init, { console_log, return_js_value, return_new_monster } from '../pkg/test_wasm';
import { GameCoreWorkerMessage } from './types';
(async () => {
  await init();
  console_log('hello from rust worker');
})();

self.addEventListener('message', (event: MessageEvent<GameCoreWorkerMessage>) => {
  console.log('test web worker');
  console_log('test from rust worker');
  const wasmRet = return_js_value();
  console.log(wasmRet);
  const monster = return_new_monster({ name: 'test', value: 'てすと' });
  console.log('monster', monster);
  self.postMessage(event.data); // テストなのでそのまま返す
});

export default {};
sample.ts
import GameCoreWorker from '@kartagraph-worker/gameCore.worker?worker'; // ?workerをつける

export function atomWithGameCoreWorker() {
  const worker = new GameCoreWorker(); // worker読み込み
  worker.onmessage = (event) => {
    const data = event.data;
    console.log('message from worker', data);
  };
  worker.postMessage({test:'data'});
}

.vscode/settings.json

試してみた結果

ログが表示されることが確認できた。
watchを使ったとき、rustのソースを更新して自動再読み込みされたときはJSが壊れてしまい、ブラウザをリロードする必要があった。

参考

Worker → WASM / WASM → Worker
Github Game-Development-with-Rust-and-WebAssembly サンプルコード
MyIssue
RustのCargo.tomlの場所がrootに無い時にVSCodeでrust-analyzerのエラーを回避する方法
The Rust Programming Language
cargo watch
wasm-bindgen
JSValue
WebAssmbly開発環境構築の本
formatter
Rust の学習に役立つサイト

Discussion