There is an ongoing tug-of-war over the future of server-side WebAssembly.
One side embraces the idea that Wasm was designed in the context of a broader web platform. Their approach to running Wasm outside of the browser is to transplant relevant parts of the web platform onto the server, and run Wasm within this browser-like context.
The other side sees Wasm as a CPU-independent bytecode, for which the browser is just one use case. Their approach is to standardize a syscall-like interface (WASI), akin to the one an operating system provides to native code.
The source of the rift is that Wasm doesn’t specify a particular interface with the outside world, by design. While Wasm itself is portable across platforms, it’s only really useful when paired with such an interface.
Although both sides generally imagine the industry converging on common standards so that code is interoperable between platforms, they are pulling towards fundamentally incompatible visions of what those common standards should look like.
This is how Cloudflare supports Rust, for example. It’s also advocated for by AssemblyScript, one of the most popular Wasm-targeting languages.
WinterCG is an effort towards cross-runtime interoperability between browsers and non-browser runtimes. It has the support of a number of vendors including Cloudflare, Deno, Netlify, and Vercel.
The ultimate vision here is a world where JS and Wasm code can both be packaged into modules and run isomorphically in the server and in the browser.
WASI comes from the Bytecode Alliance, an industry group which counts Google, Mozilla, Docker, and Fastly among its members.
WASI provides a POSIX-inspired (but deliberately non-POSIX) ABI.
Currently, most WASI calls are thin wrappers around OS syscalls that provide access to stdio, filesystems, the system clock, and random number generation. In the future, WASI’s scope will likely include network sockets and threads.
Docker creator Solomon Hykes famously tweeted that if WASI was around in 2008, Docker wouldn’t exist.
Four years after that tweet, though, WASI on its own still isn’t powerful enough to do table-stakes things like make an HTTP request.
Typically, vendors provide their own ABIs to fill such gaps: Fermyon uses wasi-experimental-http; wasmCloud provides an HTTP capability; Fastly defines a Request struct; WasmEdge provides a request API. Lunatic goes a level lower and provides a TCP API.
The problem with this state of things is that Wasm code becomes bound to a particular platform, and any language libraries that touch I/O need to be patched or replaced for each one.
For all the work that’s gone into making Wasm portable across CPU architectures, we’ve ended up with modules that are not even portable across platform vendors. After all, wasn’t that the selling point of Docker?
I’m optimistic about the Wasm component model becoming a forcing function for standardization here: as it matures, vendors will feel pressure to rip out their proprietary ABIs and replace them with components, and as they do, standard component interfaces will emerge.
There’s always a risk that the component model will just be a fifteenth competing standard. But I’m hopeful, because the tech looks solid and the industry generally seems willing to embrace it.
As much as I’m broadly in favor of (or at least, resigned to) the web platform becoming a universal operating system of sorts, I’m rooting for the WASI/components side here.
Case in point: the Rust crate
getrandom is implemented on both the web and WASI. Compare the web platform implementation to the WASI implementation.
I’m hopeful that WASI will evolve over time to cover enough of
libc that a lot of existing libraries (like database drivers and file loaders) can be compiled to it without major rewrites. If this happens, those proprietary ABIs can be torn down like scaffolding on a completed cathedral.
Until next time,