Shims and stubs
When porting a Ruby application to Wasm we deal with the following limitations with regards to libraries:
- Not every Ruby VM feature is supported by Wasm (yet); for example, Threads, sockets.
- Not every C (or Rust) extension could be compiled into Wasm.
These limitations shouldn't stop us from wasmifying our applications. Luckly, the Ruby openness makes it possible to overcome them.
Ignoring gems with uncompilable native extensions
Wasmify Rails allows you to configure the list of gems to exclude from the final Wasm build:
# config/wasmify.yml
# ...
exclude_gems:
- nio4r
- io-console
- psych
When your wasmify:build
command fails, it usually means that there is incompatible extension present. Just add it to the list and try again.
Providing shims and stubs
Wasmify Rails includes some common shims and stubs by default. For example, Thread.new { ... }
, Socket, and other APIs are available.
To provide custom shims and stubs, you have the following options.
First, you can create a file corresponding to the required feature (i.e., the feature being Kernel-required by the application) and configure the $LOAD_PATH
the way that your custom implementation is loaded first. For example, to make `require "nokogiri" pass (i.e., not fail), you:
- Create an empty file at
./my-shimsnokogiri.rb
. - Update the load path:
$LOAD_PATH.unshift File.expand_path("./my-shims")
.
Now, whenever the app tries to load Nokogiri by calling require "nokogiri"
, it loads an empty file.
The same technique could be applied if you want to provide a stub implementation (not just an empty file).
Instead of creating empty files to stub the require
calls, you can also modify the $LOADED_FEATURES
registry directly, so subsequent require
attempts wouldn't try to load the file:
$LOADED_FEATURES << $LOAD_PATH.resolve_feature_path("nokogiri").last