DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Unleashing the Power of WebAssembly to Herald a New Era in Web Development
  • An Overview of Programming Languages
  • Transforming Web Development and Cloud Computing With WebAssembly
  • Top 10 Python Applications Transforming the Real World

Trending

  • While Performing Dependency Selection, I Avoid the Loss Of Sleep From Node.js Libraries' Dangers
  • A Guide to Developing Large Language Models Part 1: Pretraining
  • Rethinking Recruitment: A Journey Through Hiring Practices
  • Fixing Common Oracle Database Problems
  1. DZone
  2. Coding
  3. Frameworks
  4. Ruby Adds Support for WebAssembly

Ruby Adds Support for WebAssembly

What does this mean for Ruby developers?

By 
Tomas Fernandez user avatar
Tomas Fernandez
·
Mar. 04, 23 · News
Likes (1)
Comment
Save
Tweet
Share
3.2K Views

Join the DZone community and get the full member experience.

Join For Free

Ruby has joined the ranks of languages capable of targeting WebAssembly with its latest 3.2 release. This seemingly minor update might be the biggest thing that has happened to the language since Rails, as it lets Ruby developers go beyond the back end. By porting their code to WebAssembly, they can run it anywhere: on the front end, on embedded devices, as serverless functions, in place of containers, or on the edge. WebAssembly has the potential to make Ruby a universal language.

What Is WebAssembly?

WebAssembly (commonly shortened as Wasm) is a binary low-level instruction format that runs on a virtual machine. The language was designed as an alternative to JavaScript. Its aim is to run applications on any browser at near-native speeds. Wasm can be targeted from any high-level language like C, Go, Rust, and now also Ruby.

Wasm became a W3C standard in 2019, opening the path to writing high-performing applications for the Web. The standard itself is still evolving, and its ecosystem is growing. Currently, this technology is receiving a lot of focus from the Cloud Native Computing Foundation (CNCF), with several projects under development.

Wasm's design sits on two pillars: portability and security. The Wasm binary can run on any modern browser, even mobile devices. For security, Wasm programs run in a sandboxed, memory-safe VM. As such, they cannot access any system resources: they can’t change the filesystem or access the network or memory.

WebAssembly Brings Portability to the Next Level

Let’s say you want to build an application targeting many systems, e.g. Linux, Windows, and macOS. What are your options?

You could use a compiled language like C and build a binary for each target.

Code is compiled into three formats: ELF binary for Linux, PE binary for Windows, and Mach binary for macOS. We have one source code and three binaries.

Compiler portability creates multiple executable files.

Or, if you can rely on having the appropriate runtime installed you could choose an interpreted language like JavaScript or one that compiles to bytecode like Java.

The code is compiled into one universal bytecode format, which is executed on the platform via a runtime environment. The diagram shows Java compilation and the JRE running on each platform.

Code is compiled into an intermediate bytecode. This system relies on having a runtime environment, or VM, installed on the client.

What if you have a container runtime in the client? In that case, you could build a Docker image for each platform type.

Diagram of a container workflow. The code is built with Docker. The process generates three types of images: one for Linux, one for Windows and one for ARM. On the client, the runtime pulls the correct image type and runs it.

Code is compiled into platform-dependent images. A container runtime is required for clients, which pulls the correct image automatically.

For Ruby developers historically, the only option was to distribute the code. That meant that users had to install the Ruby interpreter (or developers had to package the interpreter along with the application) to run the application.

The code is distributed directly. Clients must install the appropiate interpreter to execte the application.

Code is shipped directly to users, who must have the interpreter installed in their systems to be able to run it.

All these mechanisms provide portability, but at a cost: you must build, test, and distribute many images. Sometimes, you must also ship a suitable runtime with the release or tell the user to install it independently.

WebAssembly (shortened as Wasm) takes portability to the next level: it allows you to build ONE binary and run it in any modern browser.

This shows the WebAssembly workflow. Code is compiled into a unique Wasm binary, which can run unmodified on any browser. We have a single binary that runs on Linux, macOS and Linux.

WebAssembly compiles into a low-level assembly that every modern browser can execute. As a result, the same Wasm binary can run, unmodified, on every platform (even mobile).

The ability to run code at native speed has allowed developers to build sites like Figma, and Google Earth or even run Vim in the browser.

Ruby Adds Support for WebAssembly

The latest Ruby release ships with a Wasm port of the interpreter. Therefore, we can run Ruby code directly in the browser without the need for a backend.

As you can see in the example below, all it takes to get started with the Ruby Wasm port is a couple of lines. The script downloads ruby.wasm and instantiates the interpreter in the browser. After that, it takes the text of text/ruby type and feeds it into the WebAssembly program.

<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>

You can confirm that Ruby is running from the browser, i.e. not connecting with a backend, by opening the developers' tools. Here, you'll find once ruby.wasm is downloaded, no further connections are needed.

The browser console log is opened and shows: Hello, world!

Traditionally, JavaScript has been touted as the best language to learn because you have it everywhere. With WebAssembly, everyone can learn and experiment with Ruby using a browser. The output is printed in the developer's console.

You can even see the contents of ruby.wasm disassembled into text format in the “Sources” tab:

The browser’s developer tools are opened in the Sources tab. The list of sources includes a wasm folder with the Ruby interpreter downloaded. On the right pane, we see the contents of the disassembled binary in text form.

We can see the downloaded Wasm file in the browsers web developer tools.

You can check out the Wasm port online at the Ruby playground.

Working With the Sandbox

As said, Wasm programs run in a sandboxed VM that lacks access to the rest of the system. Therefore, Wasm applications do not have access to the browser, filesystem, memory or the network. We'll need some JavaScript code to send and receive data from the sandbox.

The following example shows how to read the output of a Ruby program and make changes to the page using the ruby-head-wasm-wasi NPM package:

<html>
  <script src="https://cdn.jsdelivr.net/npm/ruby-head-wasm-wasi@latest/dist/browser.umd.js"></script>
  <script>
    const { DefaultRubyVM } = window["ruby-wasm-wasi"];
    const main = async () => {
      const response = await fetch(
        "https://cdn.jsdelivr.net/npm/ruby-head-wasm-wasi@latest/dist/ruby.wasm"
      );
      const buffer = await response.arrayBuffer();
      const module = await WebAssembly.compile(buffer);
      const { vm } = await DefaultRubyVM(module);

      vm.printVersion();
      vm.eval(`
        require "js"
        luckiness = ["Lucky", "Unlucky"].sample
        JS::eval("document.body.innerText = '#{luckiness}'")
      `);
    };

    main();
  </script>
  <body></body>
</html>

The same package can also run Ruby code inside a Node project, allowing you to mix Ruby and JavaScript on the backend. You'll need to install the NPM package ruby-head-wasm-wasi for the example to work:

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

const main = async () => {
  const binary = await fs.readFile(
    //  Tips: Replace the binary with debug info if you want symbolicated stack trace.
    //  (only nightly release for now)
    //  "./node_modules/ruby-head-wasm-wasi/dist/ruby.debug+stdlib.wasm"
    "./node_modules/ruby-head-wasm-wasi/dist/ruby.wasm"
  );
  const module = await WebAssembly.compile(binary);
  const { vm } = await DefaultRubyVM(module);

  vm.eval(`
    luckiness = ["Lucky", "Unlucky"].sample
    puts "You are #{luckiness}"
  `);
};

main();

Running ruby.wasm Outside the Browser

While Wasm's primary design goal is running binary code in the browser, developers quickly realized the potential of a fast, safe, and universally portable binary format for software delivery. Wasm has the potential to become as big as Docker, greatly simplifying application deployment for embedded systems, serverless functions, edge computing, or as a replacement for containers on Kubernetes.

Running a Wasm application outside the browser requires an appropriate runtime that implements the WebAssembly VM and provides interfaces to the underlying system. There are a few competing solutions in this field, the most popular being wasmtime, wasmer, and WAMR.

The Ruby repository provides a complete example for bundling your application code into a custom Ruby image.

Limitations

Let’s remember that this is all cutting-edge tech. The whole Wasm ecosystem is moving fast. Right now, Ruby Wasm has a few limitations which significantly limit its usability in big projects:

  • No thread support.

  • Spawning processes does not work.

  • No network support.

  • The garbage collector can create memory leaks.

  • Gems and modules are unavailable unless you build a custom Wasm image.

The future Is Bright

WebAssembly opens a world of exciting possibilities. It allows Ruby developers to escape the backend. As tooling around WebAssembly improves, Ruby will be able to reach new frontiers: the browser is no longer off-limits, and there will be new opportunities to run Ruby on the edge and as serverless applications.

With the latest release, Ruby developers can begin experimenting with WebAssembly. It's the first step, for sure, and there is much more work to do before we see complex Ruby applications running in with this technology.

Thanks for reading, and happy assembling!

Ruby (programming language) WebAssembly Web development applications

Published at DZone with permission of Tomas Fernandez. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Unleashing the Power of WebAssembly to Herald a New Era in Web Development
  • An Overview of Programming Languages
  • Transforming Web Development and Cloud Computing With WebAssembly
  • Top 10 Python Applications Transforming the Real World

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!