こんにちは、rightgo09 です。
今回は Ruby 3.2.0 で実行可能になった WebAssembly を Node.js で動かしてみます。
WebAssembly の概要について
Ruby 3.2.0 について
Ruby + WebAssembly について
上記を参考にします。今回は、ブラウザでの実行や WASI での実行ではなく、Node.js での動作を目指します。
「npm packages (for JavaScript host environments)」から以下のページを参考にします。
やってみる
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 経由で実行させると高速・低メモリで実行できる、などの未来があるかもしれません。