Shims and stubs

When porting a Ruby application to Wasm we deal with the following limitations with regards to libraries:

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:

  1. Create an empty file at ./my-shimsnokogiri.rb.
  2. 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