こんにちは、HashHubの所属のエンジニア白井です。

前回の僕の投稿に続き、今回もWebAssemblyについての記事となります。

ブロックチェーン界隈で盛り上がっているRustとWebAssembly使ってWebアプリのフロントエンドを構築するTutorialをやってみました。

WebAssembly おさらい

まずは前回の記事のおさらいです。

WebAssemblyとはどういったものなのか簡単に説明していきます。

WebAssemblyとは

  • ブラウザ上で高速にプログラムを実行出来る機械語(バイナリコード)のフォーマット。
  • C/C++, Rust, Golangなどからコンパイル出来る。
  • Web技術の標準化を進めるW3Cや主要ブラウザのベンダーMozilla、Google、Apple、Microsoftが開発。
  • 現状は必要最小限の機能が搭載された試験的実装が公開された段階。
  • JavaScriptの既存資産を活用しながら、必要な部分だけを高速化することができるテクノロジーである。WebAPIを直接操作できないのでWASMからJS呼んだり、JSからWASM呼んだりして使う
  • でも1~2年経てばWebAPIも直接さわれるようになるらしい(そしたらJSいらんくなる?)

さらに詳細を確認したい方は前回の記事を御覧ください。

WebAssemblyとは

なぜRustでWebAssemblyなのか

WebAssemblyはRustだけでなくCやC++、Golangなどからもコンパイルすることが出来ますが、それぞれの言語特性がWebAssemblyにも多少反映されます。

いくつかの言語でWasmをコンパイルした場合、問題となる可能性がある事柄についてRustと比較してみました。

  • C#, Goでコンパイルした場合

ガベージコレクションなどのランタイムが大きいので、wasmファイルが2MBを超えてしまう(Golangのwasmコンパイルについて)。Rustで同じコードをコンパイルした場合2KBで済む。

  • C,C++でコンパイルした場合

C, C++はメモリ安全なコードを書くことが難しい。RustはメモリセーフなのでWasmでマルチスレッド使う時に安全性が確保される。

上記のことから、RustでWasmをコンパイルすることには多言語と比べて一定のメリットがあることが分かります。

Rust × WebAssemblyエコシステム

Rustエコシステムでは公式が用意している以下のツールを使うことで簡単にWasmを出力することが出来ます。

wasmをビルドしたり、wasmファイルをnpm registryに公開するためのツール。package.jsonとかよしなに生成してくれる。

Rustで生成したWebAssemblyとJavaScriptをつなぎ合わせるインタフェースを生成してくれるcrate。
Rustの構造体やメソッドをJavaScriptのクラスとしてラップしたり、Javascriptの関数をWasmから呼び出すためのコードを簡単にかける。

  • js-sys
    wasm-bindgenに含まれるライブラリ。jsのobjectとmethodとかpropertyを結合を担う。
  • web-sys
  • wasm-bindgenに含まれるライブラリ。window.fetchとかWebGLとかWebAudioとかWebGLとか、WebAPIを結合してくれる。

RustでWebAssemblyを使う方法

RustでWebAssemblyを使う方法は大きく分けて2つになります。

  • アプリケーション全体を構築する

ウェブアプリ全体を Rust ベースで構築。(yewとか)

  • アプリケーションの一部を構築する

既存のJavaScriptフロントエンドの内部でRustを使用。
Rustチームは現在こちらを主軸で開発をすすめている。

Rust × Wasm × Webpack Tutorialやってみた

というわけで“アプリケーションの一部を構築する”

公式のチュートリアルをやってみました。

RustでWebAssemblyを使ってHello Worldするだけの簡単なチュートリアルです。

wasm-bindgenを使ってコードを書き、Webpackからwasm-packを操作してRustをwasmファイルにコンパイルします。最後にwasmファイルをnpmパッケージとしてnpm registryに登録します。

Hello wasm-pack!

テンプレートの用意

まずはnpm initコマンドを使って公式が用意しているtemplateを展開します。

$ npm init rust-webpack your-package-name

Hello Worldするぞ

展開すると以下のコードがsrc/lib.rsにあるはずです。

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, this uses `wee_alloc` as the global
// allocator.
//// If you don't want to use `wee_alloc`, you can safely delete this.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 
// This is like the `main` function, except for JavaScript.
#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
 #[cfg(debug_assertions)]    
console_error_panic_hook::set_once();
 // Your code goes here! 
console::log_1(&JsValue::from_str("Hello world!"));

Ok(())
}

これだけだとconsole.logにHello World!と表示されるだけ、つまらないので少し手を加えていきます。

アラートを出すコードとpタグを追加して“Hello from Rust!”と表示するコードを追加してみましょう。

pub fn main_js() -> Result<(), JsValue> {   
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
#[cfg(debug_assertions)]    
console_error_panic_hook::set_once();

// Your code goes here!
console::log_1(&JsValue::from_str("Hello world!"));

let window = web_sys::window().expect("no global `window` exists");
 // アラート出してみる
window.alert_with_message("Hello World !!!");
 let document = window.document().expect("should have a document on window");
 // domを追加してみる
let body = document.body().expect("document should have a body");
let val = document.create_element("p")?;
val.set_inner_html("Hello from Rust!");
body.append_child(&val)?;
 Ok(())
}

RustをWasmにコンパイル

コードが用意できたらwasm-packを使ってRustをwasmファイルにコンパイルしていきます。

$ wasm-pack build

コマンドは以下のことを行っています。
1. Rust コードを WebAssembly にコンパイルする。
2. wasm-bindgen をその WebAssembly に対して実行し、WebAssembly ファイルを npm が理解できるモジュールにラップする JavaScript ファイルを生成する。
3. pkg ディレクトリーを作成し、その JavaScript ファイルと WebAssembly コードをそこに移動する。
4. Cargo.toml を読み、等価な package.json を生成する。
5. (もし存在するなら) README.md をパッケージにコピーする。

上記コマンドを実行すると、crate/pkg/にwasmファイルが出力されます。

crate/pkg/
crate.d.ts
crate.js
crate.d.ts
crate_bg.wasm
crate_bg.d.ts
package.json

_bg.wasmがwasmのバイナリで、crate.jsがそれをJsで読み込める形にラップしたものとなります。crate.d.tsはそれに対する typescript 型定義ファイルです。

コンパイルしたwasmファイルはjs/index.jsで読み込まれ実行されていることが確認出来るはずです。

import("../pkg").then(module => {
module.main_js();
}).catch(console.error);

Webpackでwasm-packを実行する

webpack.config.jsにwasm-pack-pluginを追加することで、Webpackからwasm-pack buildを実行出来ます。typescriptやjsをコンパイルすると同時にrustを同じようにコンパイルすることが出来ます。


module.exports = {
mode: “production”,
entry: {
index: “./js/index.js”
},
output: {
path: dist,
filename: “[name].js”
},
devServer: {
contentBase: dist,
},
plugins: [
new CopyPlugin([
path.resolve(__dirname, “static”)
]),
   // WasmPackPluginを追加する
new WasmPackPlugin({
crateDirectory: __dirname,
extraArgs: “ — out-name index”
}),
]
};

ブラウザで確認

npm startコマンドで開発用のサーバーを立ち上げます。この状態でコードを編集すると、コンソールでJavascriptだけでなくRustがコンパイルされてる様子が確認出来ます。

$ npm start

http://localhost:8080にアクセスしてHello Worldが出来ている確認しましょう。

Wasm-Packでwasmファイルをnpm registryに登録

最後に出力したファイルをnpm registryに登録してみましょう。

$ wasm-pack pack

上記コマンドでpkg以下のファイルをnpm packしてくれます。

簡単ですね。

まとめ

今回は、RustでWebAssemblyを使ってみるということで、Wasm-PackとWebpackを使った簡単なチュートリアルをやってみました。

Rust使いがWebAssemblyでJSの一部分を置き換えるのは思ったより簡単そうですね。Wasm-packを使ったRustのJsへのインテグレートがここまで簡単に出来るとは思っていなかったので正直びっくりしました。

冒頭でも述べたように、WebAssemblyをプロダクションレベルで使用するにはまだまだ機能が足りません。しかし、エコシステムも少しずつですが揃ってきています。

Rubyでサーバーサイドを開発していたプロダクトが速度アップのために一部のコードをGolangなどに置き換えることが最近では一般的なように、フロントエンドの速度を出したい部分をWebAssemblyに置き換える未来はすぐそこにあるのではということを感じました。

というわけで今回はウェブ寄りの話でしたが、RustもWasmもブロックチェーンに使われ今後盛り上がっていく技術なので、引き続き触っていこうと思います!

fressetsお知らせ

fressetsは積極的に採用を行っています!詳細は下記のリンクからご確認下さい。
Link: https://fressets.com/careers/careers-416/
Link: https://fressets.com/careers/careers-0/

HashHubお知らせ

■ステーキング事業の提供を始めました!
7月からHashHubでは、Cosmos,Tezos,IOSTの3つのトークンをステーキング出来るサービス「Sanka Network」を提供し始めました。本サービスのご利用をご検討の方は、下記のWEBサイトからお問い合わせください。

Sanke Network:https://www.sanka.network/

■HashHubでは下記のポジションを積極採用中です!
・コミュニティマネージャー
・ブロックチェーン技術者・開発者
・ビジネスディベロップメント
詳細は下記Wantedlyのページをご覧ください。

Wantedly:https://www.wantedly.com/companies/hashhub/projects

■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。

HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo


RustでWebAssemblyやってみた。 was originally published in Blockchain Engineer Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

  • このエントリーをはてなブックマークに追加
 
Recommend article