Running WASI in Javascript with Wasmer-JS

Aaron Turner
Oct 1, 2019 · 5 min read

WebAssembly System Interfaces (WASI) is an exciting new specification that allows running POSIX-like applications anywhere, safely and securely with WebAssembly.

However, there is not much support for running WASI modules in both Node and the browser. We’ve been working hard on a solution for this problem and with the help of the WebAssembly community I am stoked to share what we made! 🎉

Today, drumroll please… 🥁, we are excited to announce Wasmer-JS! A collection of open-source, installable packages for running WASI modules in Node and the browser! 📦

Using these new packages we are launching we were able to get QuickJS, compile it to WASI, and run the QuickJS Wasm module in the browser. Thus in the QuickJS example, you can compile a JavaScript engine to WebAssembly, that is then run in the browser using the WebAssembly runtime, to run JavaScript. Meaning, you can now finally run JavaScript within your web browser! 🤡 (Joking!)

Here is an example of running the Javascript Interpreter quickjs in the Browser with the @wasmer/wasm-terminal package:

Gif of running QuickJS in the Browser with @wasmer/wasm-terminal

This demo shows off what could be done with running Wasm / WASI within Javascript. Similar to our example above, PSPDFKit is currently using Duktape compiled to Wasm to sandbox Javascript execution. Other ideas are:

  • If you are a web developer, you could compile your favorite tool written in a WASI compiled language. That you can then run, and use it’s output in your Node or web application. 🛠

Now that we have a good idea of what Wasmer-JS can do, let’s take a step back and see how it works. 🤔

Why is running WASI in JavaScript difficult?

WASI has an awesome simple, low-level POSIX-like API and the team did a great job in its design. However, here are some reasons why running WASI in JavaScript is difficult:

  • WASI modules expect certain imports from the host runtime, which are not currently available in web browsers or Node. 🌐

There are some solutions that solve some of these issues. The awesome folks at Mozilla have a web polyfill that runs in the browser by polyfilling the WASI imports. This can be used to show the standard output of the run module. But it does not solve all of the issues above, does not support standard input can not run WASI modules that use i64 imports, and is not meant to be used in a modern JavaScript project. Next, there is node-wasi made by devsnek. This project polyfills the WASI imports, and leverages Node’s fs implementation to provide file system access. It also could be used in a modern Node project, but it can not run WASI modules that use i64 imports or be used in the browser.

By leveraging the great work done in node-wasi, we were able to expand on their work to solve all of these issues to get WASI running in both the browser and Node. 🎉

How does Wasmer-JS run WASI in JavaScript?

Wasmer-JS can run WASI modules in JavaScript using its following packages:

  • @wasmer/wasi is a WASI implementation based on and extending from node-wasi. It adds types as it is written in TypeScript. It is following the same API as the Node WASI fork. It also works in the browser using the appropriate bindings. 🌐

Let’s take a look at an example:

To see all of these packages working together at a greater scale, we can take a look at the @wasmer/wasm-terminal package.

This package offers a a terminal-like interface using Xterm.js, that can fetch and run Wasi modules using the other Wasmer-JS packages. It even supports custom Javascript callback commands, common terminal hotkeys, tab autocomplete, piping between modules, and running commands in parallel web workers using Comlink! 😍

Thank you!

This announcement is super exciting, and we are proud of the work we have accomplished! 🎉 But this definitely could not have been done without the help of the WebAssembly community, and the open source projects we build our work on top of. We want to give a huge thank you to the authors of node-wasi, wasm-pack, memfs, Xterm.js, Comlink, and the other dependencies we are building on top of! 🙏

And most of all, Thank YOU for reading this article! Please feel free to try out the packages in Wasmer-JS. All of these things are open-source, and contributions are definitely welcome! Contributions can be opening an issue, submitting a PR, or even telling a friend! 💪

Feel free to reach out on Twitter or Spectrum, and we are very excited to see what you build! Cheers! 🍻

Wasmer

Universal WebAssembly runtime

Thanks to Syrus Akbary and Mark McCaskey

Aaron Turner

Written by

Skate. Music. Video Games. Code. Developer / Developer Relations at Wasmer. All opinions expressed are my own. Please excuse the spelling, I am a lazy typist.

Wasmer

Wasmer

Universal WebAssembly runtime

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade