🐈

JavaScriptからWebAssemblyの関数を呼び出す: Rustが征く(3)

2021/08/16に公開

wasm-bindgenをどう使うか

関連記事:
WSL2で作るWindows開発環境: Rustが征く(1)
wasmerでWebAssemblyの門を叩く: Rustが征く(2)
JavaScriptからWebAssemblyの関数を呼び出す: Rustが征く(3)

------------------- ↓ 前書はここから ↓-------------------

RustネイティブWebAssemblyランタイムと来たので、
次はWeb側と接続する。
WebAssemblyはその名前の通りWeb上での使用を前提に設計されているので、
JavaScriptとの接続が容易になっている。

バンドラーは既存のJavaScript用のものを活用する。
パックツールにはwasm-packを使用。

導入部分で一番参考になるのはここかな
https://developer.mozilla.org/ja/docs/WebAssembly/Rust_to_wasm

これの流れで進めていこう

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪

------------------- ↓ 本題はここから ↓-------------------

Rustのインストール

以下参照のこと
WSL2で作るWindows開発環境: Rustが征く(1)

必要コマンドを追加

Rustインストールと併せて各種コマンドも追加しておく

rustup target add wasm32-unknown-unknown
cargo install cargo-edit miniserve wasm-pack

結構時間がかかるので飲み物でも取りに行こう

(-.-)y-~~ 一服してきま~す

cargoコマンドでプロジェクト作成

cargo newにてcargoプロジェクトを作成する
名前は何でも良いが hello-bindgen としておこう

cargo new --lib hello-bindgen
cd hello-bindgen

Cargo.tomlの修正

生成されたCargo.tomlは内容が不十分なので修正する。
この辺手書きなのがダルい。
ビルドチェックも併せて実行

printf '[lib]\ncrate-type = ["cdylib"]\n' | tee -a ./Cargo.toml
cargo add wasm-bindgen
cargo check --release --target wasm32-unknown-unknown
Cargo.tomlは最終的にはこんな感じ
./Cargo.toml
[package]
name = "hello-bindgen"
version = "0.1.0"
edition = "2018"

# See more keys and their defini・・・・

[dependencies]
wasm-bindgen = "0.2.74"
[lib]
crate-type = ["cdylib"]

src/lib.rs実装

設定が済んだので実装作業開始。
src/lib.rsにデフォルトで記述しているのはテストなので削除して以下に書き換える。

src/lib.rs
extern crate wasm_bindgen;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern {
    pub fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    alert(&format!("Hello, {}!", name));
}

(・∀・) 実装完了

ビルド開始

cargo build --release --target wasm32-unknown-unknown
wasm-pack build --release --target web -d ./dist/js

index.htmlを用意

最後ににindex.htmlを用意しておく
Rust側で設置したgreet関数をJS側から呼び出す

./dist/index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
</head>
<body>
<script type="module">
import init, { greet } from './js/hello_bindgen.js';
(async () => {
  await init()
  greet('Bindgen')
})()
</script>
</body>
</html>

Webサーバー起動

Webサーバーを起動してアクセスしてみよう

miniserve ./dist

http://localhost:8080/index.html

(^_^)b はろ~

------------------- ↓ 後書はここから ↓-------------------

設定項目を整理

今回、最小行程ではろ~わ~るどするために、
コマンドが長くなったり、
Node.jsを使わなかったりしたが、
いろいろ不便な部分が出てしまう。
なので、設定項目を調整しよう

ビルドターゲットの固定化

毎回--target=wasm32-unknown-unknownって打つのは長くなるので短くしたい。
targetを変更することはほぼないので固定化しておこう。
./.cargo/config.toml というファイルを作成して、
ターゲットを記述する。

cd /path/to/hello-bindgen
mkdir .cargo
printf '[build]\ntarget = "wasm32-unknown-unknown"\n' | tee .cargo/config.toml
cargo clean
cargo check --release

wasm-packでビルドするとwasm32-unknown固定になるっぽい

ツールチェインの固定化

ツールチェイン指定でnightly使ってねっていうのが稀に良くある。
コマンドラインでやると手間なので、
こちらも固定化したい。

以下のようにnightlyを追加して一覧を見ると

rustup toolchain add nightly
rustup component add rust-src
rustup toolchain list
  stable-x86_64-unknown-linux-gnu (default)
  nightly-x86_64-unknown-linux-gnu

では設定を追加して実行してみる。
./rust-toolchain.toml を作成し、
ツールチェインを設定する。

printf '[toolchain]\nchannel = "nightly"' | tee rust-toolchain.toml
rustup toolchain list
  stable-x86_64-unknown-linux-gnu (default)
  nightly-x86_64-unknown-linux-gnu (override)

(override) と上書きされていることがわかる

🤔Rustの設定ファイルってとっ散らかり過ぎじゃね?

rollup.jsでビルド行程をまとめようかと思ったけど、
長くなったのでそれは別の機会に。

謎のエラー

Uncaught TypeError: Failed to resolve module specifier "wasm_thread.js". Relative references must start with either "/", "./", or "../".

🤔ナニコレ?

WebAssembly関連ファイルのパス指定をファイル名だけにしたときに発生。
なんか、相対パス的に書けとのこと。

- import init from 'hello_bindgen.js';
+ import init from './hello_bindgen.js';

理由?
セキュリティてきなさむしんぐやろ。
しらんけど。

Discussion