🦁
WebGLチュートリアルをRustのWebAssemblyで書く 〜その1〜
WebGLのチュートリアルをWebAssemblyで書きます。Rustで、wasm-bindgenを使います。今回は環境構築について多めです。
npm, webpack and typescript
wasm-pack new PROJECT_NAME && cd PROJECT_NAME
npm init -y
npm install --save-dev webpack webpack-cli http-server typescript ts-loader
package.json
...
"scripts": {
"server": "wasm-pack build && webpack && http-server"
},
...
webpack.config.js
const path = require("path");
const dist = path.resolve(__dirname, "dist");
module.exports = {
//mode: "production",
mode: "development",
entry: {
index: "./js/index.ts",
},
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
output: {
path: dist,
filename: "[name].js",
},
experiments: {
asyncWebAssembly: true,
},
};
asyncWebAssemblyを設定します
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node"
}
}
上記を参考にしています
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<title>test server</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/index.js"></script>
</body>
</html>
js/wasm.ts
import * as wasm from "../pkg/PROJECT_NAME.wasm";
import { __wbg_set_wasm } from "../pkg/PROJECT_NAME_bg.js";
__wbg_set_wasm(wasm);
export * from "../pkg/PROJECT_NAME_bg.js";
js/index.ts
import { start } from "wasm";
start();
以前はjs/index.tsに下記を書くだけでも動いていたと思いますが、2023/2/4現在上記のようにしないとwasmファイルがwebpackでバンドルされませんでした
//参考
import { start } from "../pkg";
start();
Rust
Cargo.toml
...
[dependencies]
wasm-bindgen = "0.2.63"
console_error_panic_hook = { version = "0.1.6", optional = true }
wee_alloc = { version = "0.4.5", optional = true }
wasm-bindgen-futures = "0.4.33"
[dependencies.web-sys]
version = "0.3.60"
features = [
"Window",
"Document",
"HtmlElement",
"HtmlCanvasElement",
"WebGl2RenderingContext",
]
...
.cargo/config.toml
[build]
rustflags = [
"--cfg=web_sys_unstable_apis",
]
src/lib.rs
use wasm_bindgen::prelude::*;
use web_sys::WebGl2RenderingContext as GL;
#[wasm_bindgen]
pub async fn start() -> Result<(), JsValue> {
let window = web_sys::window().ok_or_else(|| JsValue::from_str("no window exists"))?;
let document = window
.document()
.ok_or_else(|| JsValue::from_str("should have document"))?;
let app = document
.get_element_by_id("app")
.ok_or_else(|| JsValue::from_str("no #app exists"))?;
let canvas = document
.create_element("canvas")?
.dyn_into::<web_sys::HtmlCanvasElement>()?;
canvas.set_attribute("width", "640")?;
canvas.set_attribute("height", "480")?;
app.append_child(&canvas)?;
let gl = canvas
.get_context("webgl2")?
.ok_or_else(|| JsValue::from_str("fail to get context"))?
.dyn_into::<web_sys::WebGl2RenderingContext>()?;
gl.clear_color(0.0, 0.0, 0.0, 1.0);
gl.clear(GL::COLOR_BUFFER_BIT);
Ok(())
}
npm run server
Discussion