Ruby WebAssembly WASM/WASI Guide for Dummies (2023)
In this article we try to focus on Offical CRuby things
Last Updated Jan 13, 2023 - This is a working document so please stay tuned for updates, looks like an offical 3.2.0 ruby.wasm release is coming soon, hopefully before February 2023
Official Repos
- ruby/ruby (Actual Webassembly code) - https://github.com/ruby/ruby/tree/v3_2_0/wasm
- Instructions here are only for making your own custom/optimized builds. This is not required if you just use the Pre-built builds mentioned below>
- Manual Build Instructions (Advanced users only) - https://github.com/ruby/ruby/tree/v3_2_0/wasm/README.md
- ruby/ruby.wasm (Official Prebuilt Builds) - https://github.com/ruby/ruby.wasm
- We are still waiting on official post-3.2.0 release - https://github.com/ruby/ruby.wasm/issues/144
- Latest pre-release builds (post-v0.5.0) have added OpenSSL. are in pre-release, see the github releases page, https://github.com/ruby/ruby.wasm
- 2 Ways to use this
- For the Web:
- They published Ruby compiled to WebAssembly/WASI executables as an NPM package called ruby-wasm-wasi (or ruby-head-wasm-wasi). As a result, users who want to use WebAssembly/WASI compatible Ruby do not need to build it themselves.
- Documentation for NPM package is visible here, https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi-head
- Browser Quickstart: https://github.com/ruby/ruby.wasm/tree/ruby-head-wasm-wasi-0.5.0/packages/npm-packages/ruby-head-wasm-wasi#quick-start-for-browser
- API Docs: https://github.com/ruby/ruby.wasm/tree/ruby-head-wasm-wasi-0.5.0/packages/npm-packages/ruby-head-wasm-wasi#apis
- Javascript-WASM interoperability layer source code: https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi-head/src/index.ts
- They published Ruby compiled to WebAssembly/WASI executables as an NPM package called ruby-wasm-wasi (or ruby-head-wasm-wasi). As a result, users who want to use WebAssembly/WASI compatible Ruby do not need to build it themselves.
- Outside of the Web:
- Packaging and Running your own WASM binary: https://github.com/ruby/ruby.wasm#quick-example-how-to-package-your-ruby-application-as-a-wasi-application
- Can be used as a command-line utility or as a library embedded in a larger application.
- For the Web:
Glossary of Terms
- WASM - Synonym for WebAssembly
- WASI - WebAssembly System Interface. WASI is an effort to define a standard set of syscalls for WebAssembly modules, allowing WebAssembly modules to not only be portable across architectures but also be portable across environments by immplementing this standard set of system calls. WASI does not rely on JavaScript at all.
- Emscripten - Alternative to WASI. Not recommended to use this anymore. The community is charging forward with WASI.
- wasi-vfs - Packages all files and assets into a single binary file. This library is not Ruby-specific and is designed to be used by all WASI-enabled WebAssembly applications.
- Wasmtime / Wasmer - Used to run WebAssembly code outside of the Web, and can be used both as a command-line utility or as a library embedded in a larger application. So this is not needed for Web-style applications unless you want to run the binary locally during development.
List of important developers
- Yuta Saito - https://github.com/kateinoigakukun
- Main researcher who led WASM efforts and is now core maintainer of this part of Ruby. If you see his contributions somewhere then its going to be an “official” WASI library
- Yusuke Endoh - https://github.com/mame - “Mentor” Researcher
Supports script type text/ruby when using browser.script.iife.js
<html>
<script src="https://cdn.jsdelivr.net/npm/ruby-head-wasm-wasi@0.5.0/dist/browser.script.iife.js"></script>
<script type="text/ruby">
puts "Hello, world!"
</script>
</html>
OR with local/remote files
<script type="text/ruby" src="hello.rb"></script>
How to use javascript (with any pre-built binary with -js)
require "js"
document = JS.global[:document]
button = document.getElementById("draw");
result = document.getElementById("result");
button.addEventListener("click") do |e|
puts e
luckiness = ["Lucky", "Unlucky"].sample
result[:innerText] = luckiness
end
Example Apps
- Posting Puzzle (Horizonal Tetris)
- This application just uses Ruby only for the game logic, not any rendering
- View App: https://mame.github.io/posting-puzzle/
- Source Code: https://github.com/mame/posting-puzzle/blob/main/index.html
- IRB-like (uses JS webworker to load it, mocks some stdlib gems, and other interesting techniques)
- View App: https://irb-wasm.vercel.app/
- Source Code: https://github.com/kateinoigakukun/irb.wasm
- Todolist
- ruby.wasm Wiki Showcase
- https://github.com/ruby/ruby.wasm/wiki/Showcase
- Many of the examples here are a little contrived I think the above ones are better for learning
Additional Reading:
- Official Examples (see each html file and script-src folder)
- Research Final Report from Ruby Grant
- Research Mentor Final Report from Ruby Grant