LoginSignup
5

More than 5 years have passed since last update.

爆速でjsでWebAssemblyを動かす

Last updated at Posted at 2018-05-14

概要

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からアクセスできるようにするための記述である。

src/lib.rs
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.wasmjs_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.jsonwebpack.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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5