概要

jsからRustにより出力されたwasmを呼び出すための方法を記載する。
Rustを動かすための環境構築の方法は“プログラミング言語Rust: 2nd Edition”の日本語版PDFを作成したを参考にしていただきたい。

(2019/09/26 追記)しばらく前にこれやってみて久しぶりに動かしたけど動かない、という人は、以下を実行すればなおる。

rustup update
rustup update nightly
cargo install -f wasm-bindgen-cli

早速本題に入っていく。

クロスコンパイルのターゲットの追加

これを使ってwebassemblyにしてください、という指定を行う。ここではwasm32-unknown-unknownを追加する。wasm-bindgenのgitではnightlyの指定をしていないが、私の環境ではうまく動かなかったので+nightlyを指定してターゲットを追加する。
参考:nightlyのインストール方法

rustup target add wasm32-unknown-unknown
# もしくは
rustup target add wasm32-unknown-unknown --toolchain nightly

Rustのプロジェクトを作成

プロジェクトを作成する。今回はwasmをモジュールとして読み込ませたいので、–libをつける。

cargo new js-hello-world --lib
cd js-hello-world

Cargo.toml

以下のように記載する。cdylibはRustコードをコンパイルするためのツールで、wasm-bindgenはjsでrustのAPIを呼び出すために必要、という理解でよい。

[package]
name = "js-hello-world"
version = "0.1.0"
authors = ["gamushiro <>"]

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

モジュールを書く

細かな文法等の説明はここではしないが、引数に応じてalert()を行うgreetという関数をつくる。
#[wasm_bindgen]をしている箇所ではwasm_bindgenを利用した際に、javascriptからアクセスできるようにするための記述である。

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

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

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

その後ビルドを行う(ここでも私の環境ではnightlyを指定した。そうしないとビルドが通らなかった)。

cargo build --target wasm32-unknown-unknown
# もしくは
cargo +nightly build --target wasm32-unknown-unknown

wasm-bindgen-cliのインストール

wasm-bindgenコマンドを利用するためにwasm-bindgen-cliをインストールする。
wasm-bindgenコマンドによりwasmファイルとwasmを呼び出すjsのインターフェースの役割をするjsファイルが出力される。

cargo install wasm-bindgen-cli

wasm-bindgenの実行

もともとビルドされたwasmファイルを1番目のオプションに、出力先を2番目のオプションを指定する。
js_hello_world_bg.wasmとjs_hello_world.jsが出力されるが、出力されたファイルを使ってjavascriptからアクセスをする(後程jsを書く際に再度触れる)。ちなみに、プロジェクト名がハイフン区切りの場合でも、出力されているwasmファイルはアンダースコア区切りになっていることに注意。

wasm-bindgen target/wasm32-unknown-unknown/debug/js_hello_world.wasm --out-dir .

大体これでwasm側の準備ができたので、これからhtmlをサーブするための準備をする。

html

特に気にせず。

<html>
  <head>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
  </head>
  <body>
    <script src='./index.js'></script>
    hello from rust !!
  </body>
</html>

js

ここでwasm-bindgenにより出力されたjsファイルを読み込む。そうすることでwasmファイルへのアクセスが可能になり、greetメソッドを利用できるようになる。

const js = import("./js_hello_world");

js.then(js => {
  js.greet("hello!!");
});

サーバの準備

ここまでできたらサーバは何でもよいのだが、私はwebpackのビルトインサーバを利用して動作を確認するため、利用したpackage.jsonとwebpack.js.configを以下に記載する。

package.json

{
    "scripts": {
      "serve": "webpack-dev-server"
    },
    "devDependencies": {
      "html-webpack-plugin": "^3.2.0",
      "webpack": "^4.11.1",
      "webpack-cli": "^3.1.1",
      "webpack-dev-server": "^3.1.0"
    }
}

webpack.js.config

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    plugins: [
        new HtmlWebpackPlugin()
    ],
    mode: 'development'
};

これで

yarn run serve

を行いlocalhost:8080にアクセスすれば画面読み込み時にアラートが出てくる。
ソースコードはGitHubに公開しています。

参考

Rust単体でWebAssemblyをコンパイルする(Emscripten無し)
JavaScript to Rust and Back Again: A wasm-bindgen Tale – Mozilla Hacks – the Web developer blog

广告
将在 10 秒后关闭
bannerAds