cargo 1.40.0-nightly (8b0561d68 2019-09-30)
node v10.15.3
Rustのチュートリアルだとnpmのパッケージを作れとか、ブラウザで動かすには余計な回り道が書かれてて「とりあえずブラウザでwasm動かしてみたい」という場合に、動かすまでの敷居が逆に高くなっている気がします。
というわけで、最速でalertを出すサンプルをブラウザで実行する方法を書いてみます。
試したのは Firefox-70.0(64bit) on Ubuntu 18.04 です。
Rustでwasmが出力できて、npmが動く環境はすでにあるものとします。
必要なものをインストール
cargo install wasm-pack
npm install -g node-static # wasmを配信できるstaticサーバ。入れとくと便利
node-staticをinstallしておくと、次のコマンドでファイル配信できます
static 配信するディレクトリ
チュートリアルに沿って進める
プロジェクトを作成します。
cargo new --lib hello-wasm
cd hello-wasm
src/lib.rsの内容をチュートリアルに従ってまるっと変更します。ただし最近のRustではexternの行はいりません。useだけで自動的にexternされます。
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
Cargo.tomlにlibとdependenciesの設定を記述します。
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
ビルドする
ここが少しかわります。npmパッケージにしないのでscopeは必要ない代わりに、ブラウザ用にtargetにwebを設定します。
wasm-pack build --target web
pkgというディレクトリができて、その中に実行に必要なファイルとTypeScript用の型定義ファイルが生成されています。
この時点でwasmファイルが一気に小さくなっています。これが嬉しいですよね!
index.htmlを作成する
wasm-packで生成されたpkgディレクトリの中に、実行用のindex.htmlを配置します。<script>の内容がチュートリアルと異なります。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello-wasm example</title>
</head>
<body>
<script type="module">
import * as mod from "./hello_wasm.js";
(async () => {
await mod.default();
mod.greet("rust test");
})();
</script>
</body>
</html>
wasm-bindgen(wasm-pack経由)で出力されたファイルを使うために、typeにmoduleを指定しています。
そのままgreet()を使いたいところですがモジュール内のwasmという変数が未初期化なので、先に初期化関数であるdefault()を実行します。
default()はPromiseを返すので、.then か async/await を使って待機した後に処理を記述します。今回はawaitでdefault()の完了を待ってgreet()を実行しています。
動かしてみる
node-staticが入っていれば、pkgディレクトリを指定して実行するだけです。
static pkg
localhost:8080にアクセスすると、alertが表示されます。