Rust+Viteでwasmを動かすところ
Viteで用意したフロントからwasmを動かすところまで。
環境
- rustc: 1.69.0
- wasm-pack: 0.11.0
- vite: 4.3.5
Rust側の準備
cargo newでプロジェクトを作成する。
src/lib.rsを作成し、最低限以下のコードを書いておく。
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
use winit::event::{Event, WindowEvent};
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
pub async fn run() {
#[cfg(not(target_arch = "wasm32"))]
{
env_logger::init();
}
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
}
let event_loop = winit::event_loop::EventLoop::new();
let window = winit:🪟:WindowBuilder::new()
.with_title("Your Project")
.build(&event_loop)
.unwrap();
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
web_sys::window()
.and_then(|win| win.document())
.and_then(|doc| {
let dst = doc.get_element_by_id("wasm-canvas")?;
let canvas = web_sys::Element::from(window.canvas());
dst.append_child(&canvas).ok()?;
Some(())
})
.expect("Could not get canvas element");
}
event_loop.run(move |event, _, control_flow| {
*control_flow = winit::event_loop::ControlFlow::Poll;
match event {
Event::WindowEvent {
ref event,
window_id,
} if window_id == window.id() => match event {
WindowEvent::CloseRequested => *control_flow = winit::event_loop::ControlFlow::Exit,
_ => {}
},
_ => {}
}
});
}
ここまででcargo runを実行すると、真っ黒なWindowが表示される。
React側の準備
以下のコマンドを実行し、viteでReact+Typescript+SWCのプロジェクトを作成する。
yarn create vite
プロンプトの選択肢はReactとTypescript + SWCを選択する。
viteで作成されたデフォルトのmain.tsxでは<React.strictMode>が使われているので、これを削除しておく。
React.strictModeでは副作用のチェックのために2回レンダリングされる様子。
そのため、wasmの初期化処理が2回呼ばれてしまい、エラーになる。
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<App />
);
App.tsxも以下のように書き換える。
pkg/project.jsは後述のwasm-pack buildで生成されるファイル名を指定する。
import { useEffect } from "react";
import "./App.css";
import init from "../pkg/project.js";
function App() {
useEffect(() => {
init().then(() => {
console.log("WASM initialized");
});
});
return <div id="wasm-canvas"></div>;
}
export default App;
wasmのビルド&実行
以下のコマンドを実行し、wasmをビルドする。
wasm-pack build --target web --out-dir ./path/to/vite-project/pkg
viteのプロジェクト内でyarn devを実行すると、真っ黒なcanvasが表示される。