ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

Ruby 3.2.0 の WebAssembly を Node.js で実行する

こんにちは、rightgo09 です。

今回は Ruby 3.2.0 で実行可能になった WebAssembly を Node.js で動かしてみます。

WebAssembly の概要について

developer.mozilla.org

Ruby 3.2.0 について

www.ruby-lang.org

Ruby + WebAssembly について

github.com

上記を参考にします。今回は、ブラウザでの実行や WASI での実行ではなく、Node.js での動作を目指します。

npm packages (for JavaScript host environments)」から以下のページを参考にします。

github.com

やってみる

npm install によって、Ruby 本体の WebAssembly ファイルをダウンロードします。いろいろなサンプルにあるとおり、現在 Ruby による WebAssembly の実現には Ruby 本体の WebAssembly ファイルを用意する必要があります。

$ mkdir ruby_wasm_nodejs
$ cd ruby_wasm_nodejs
$ npm install --save ruby-head-wasm-wasi@latest

node_modules ディレクトリに Ruby 本体の WebAssembly ファイルがあることがわかります。

$ wc -c node_modules/ruby-head-wasm-wasi/dist/ruby*
 26677439 node_modules/ruby-head-wasm-wasi/dist/ruby+stdlib.wasm
 43029038 node_modules/ruby-head-wasm-wasi/dist/ruby.debug+stdlib.wasm
 10499679 node_modules/ruby-head-wasm-wasi/dist/ruby.wasm
 80206156 total

約 80 MB ものバイナリが作成されています。

動作自体には ruby.wasm があれば問題ありませんが、こちらには Ruby 標準ライブラリがないので、使用する必要がある場合は適宜 ruby+stdlib.wasm を選択する必要があります。

開発中はスタックトレースが可能な ruby.debug+stdlib.wasm が便利なようです(未確認)。

続いて、以下のファイルたちを作成します。

hello.rb

puts "Hello from hello.rb"

today.rb

require "date"

def get_today
  Date.today
end

index.mjs

import fs from "fs/promises";
import { DefaultRubyVM } from "ruby-head-wasm-wasi/dist/node.cjs.js";

const main = async () => {
  const binary = await fs.readFile(
    // "./node_modules/ruby-head-wasm-wasi/dist/ruby.wasm"
    // Ruby の Date モジュールを使いたいので、stdlib 包含版を使う
    "./node_modules/ruby-head-wasm-wasi/dist/ruby+stdlib.wasm"
  );
  const module = await WebAssembly.compile(binary);
  const { vm } = await DefaultRubyVM(module);

  vm.printVersion();

  vm.eval(await fs.readFile("./hello.rb"));

  const today = vm.eval(await fs.readFile("./today.rb"));
  console.log(today.call("get_today").toString());
};

main();
$ node -v
v18.13.0

$ node --no-warnings --experimental-wasi-unstable-preview1 index.mjs 
ruby 3.2.0dev (2022-11-11T22:40:31Z master 0a9d51ee9d) [wasm32-wasi]
Hello from hello.rb
2023-01-10

実行できました。 DefaultRubyVM を使用することで、Node.js で WebAssembly を使用する際に必要となるグルーコードが実行されているようです。

まとめ

Ruby のコードが Node.js で実行できました。とはいえ現在における用途はかなり限定的になりそうですが、たとえば、AWS Lambda において Ruby を直接実行するのではなく、WebAssembly 経由で実行させると高速・低メモリで実行できる、などの未来があるかもしれません。


unifa-e.com