🌟

wasm-packのターゲットをno-moduleにしたときの利用法

2021/10/11に公開

マルチスレッドとかでは重要だったりするが

関連記事:

Rustが征くシリーズ過去記事

wasm-packのビルドオプションにtargetというのがある。
ここで選択できるオプションに

  • nodejs
  • bundler(webpack)
  • deno
  • web
  • no-module

というのがある。
nodejs, bundler, denoは言うまでも無いが、
webとno-moduleで生成されるWebAssemblyモジュールは同じもの
(チェックサムも一致する)

となると生成されるjsファイルが異なるのだが、
どう使い分けるのかというのが今回の話。
targetを整理すると

taret generated
nodejs commonjs
deno for deno
bundler webpack
no-module iife
web ES Module

という感じか。
iifeとは即時実行関数のことで、
ファイルをロードすると wasm-bindgenというグローバル変数が取得できる

ES Moduleはimport/exportのES6フォーマットのこと。

以下に書いた記事
[JavaScriptからWebAssembly関数を呼び出す: Rustのすゝめ(3)]
ではtarget=webの場合の内容なので、
今回はno-moduleの場合を記述する。

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

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

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

cargo newにてcargoプロジェクトを作成する
今回はいろいろ省略するためにwasm-packデフォルトテンプレートを使用

cargo install cargo-edit wasm-pack wasm-bindgen-cli miniserve
wasm-pack new hello-nomodule
cd hello-nomodule

ビルド開始

wasm-pack build --release --target no-modules -d ./dist/js

index.htmlを用意

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

./dist/index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
</head>
<body>
<script src="./js/hello_nomodule.js"></script>    
<script type="module">
(async () => {
  const {greet} = await wasm_bindgen('./js/hello_nomodule_bg.wasm')
  greet()
})()
</script>
</body>
</html>

Webサーバー起動

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

miniserve ./dist

http://localhost:8080/index.html

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

結果は前回の記事とだいたい同じだが、
HTMLでの使い方が少し違う
(greet関数の使い方は本筋じゃないのでスルーで)

web
<script type="module">
import init, { greet } from './js/hello_bindgen.js';
(async () => {
  await init()
  greet('Bindgen')
})()
</script>
no-modules
<script src="./js/hello_nomodule.js"></script>    
<script type="module">
(async () => {
  const {greet} = await wasm_bindgen('./js/hello_nomodule_bg.wasm')
  greet()
})()
</script>

(・ω・) wasm_bindgen って変数はどっから来た?

上記で述べたように no-modules=iifeなので、
js/hello_nomodule.jsを読み込んだ時点で生成されている。
HTML上で使う分にはこれでいいのだが、
JavaScript上で呼び出そうとすると生成されたものをそのまま使おうとするとちょっと扱いづらい。

なので、no-module版のjsファイルの最終行に以下を追加する

./js/hello_nomodule.js
+ export default wasm_bindgen

ビルドコマンドは以下のような感じか。

wasm-pack build --release --target no-modules -d ./dist/js
printf '\nexport default wasm_bindgen\n' | tee -a ./dist/js/hello_nomodule.js

Discussion