The most performant JavaScript Service Workers server thanks to Rust and SpiderMonkey
Founder & CEO
October 27, 2023
Today we are incredibly excited to announce WinterJS (wasmer/winterjs
package).
WinterJS is a JavaScript Service Workers server written in Rust, that uses the SpiderMonkey engine to execute JavaScript (the same engine that Firefox uses). We chose to follow the WinterCG specification to aim for maximum compatibility with other services such as Cloudflare Workers, Deno Deploy and Vercel (hence the name WinterJS).
WinterJS is not only blazing fast™️ but can also be compiled to WebAssembly thanks to WASIX and thus also run fully with Wasmer.
Let's see how it works. We'll start by creating a simple serviceworker.js
file that just returns a simple "hello world";
addEventListener('fetch', (req) => {
req.respondWith(new Response('hello'));
});
Running it with WinterJS is as simple as this:
$ wasmer run wasmer/winterjs --net --mapdir /app:. /app/serviceworker.js
WinterJS can also be run natively with Rust (
cargo install --git https://github.com/wasmerio/winterjs && winterjs serviceworker.js
). You can find the source code of WinterJS in the GitHub repo: https://github.com/wasmerio/winterjs
Thanks to the WASIX capabilities of WinterJS, the JavaScript service worker can also be deployed to Wasmer Edge. Check the working demo here: https://wasmer-winter-js-sample-worker.wasmer.app/
And now that you have seen a sneak peak on how to use WinterJS, lets do a deep dive on our journey building it.
Before starting on the quest of creating a JavaScript Service Workers server, we analyzed the Javacript runtimes that we could use.
Here are the main requirements we have for such JavaScript runtime:
And here are the JS runtimes that we analyzed:
peformance.now()
, addEventListener
, …)peformance.now()
, addEventListener
, …)After a few runtime trials we set on SpiderMonkey as the most reasonable approach that fitted our tight timeline.
So we begin porting. We started with a fork of mozjs that supported a new compilation tier called PBI (Portable Baseline Interpreter).
After some work on the mozjs build system to target WASIX, we were able to bypass most of the issues, except one: the bindings generation.
The bindings that allow using the SpiderMonkey C++ API from Rust were automatically generated using c-bindgen. Plugging those bindings onto WASIX was a challenge so we simply decided to target a 32 bit system and modify them by hand (a 32,000 file!) to target WASIX.
And voilá… everything worked!
However, after adding a few missing resources to JS, we realized that perhaps mozjs didn’t have the easiest API to use:
unsafe extern "C" fn base64_encode(cx: *mut JSContext, argc: u32, vp: *mut Value) -> bool {
let args = CallArgs::from_vp(vp, argc);
if args.argc_ < 1 {
return false;
}
let source = js_try!(cx, raw_handle_to_string(cx, args.get(0)));
let result = ::base64::engine::general_purpose::STANDARD.encode(bytes);
rooted!(in(cx) let mut rval = UndefinedValue());
result.to_jsval(cx, rval.handle_mut());
args.rval().set(rval.get());
true
}
Thankfully, the spiderfire project had been working on improving the API surface for using SpiderMonkey from Rust.
So the example laid out before now looks way simpler and easier to read/maintain:
#[js_fn]
fn btoa<'cx>(val: String) -> String {
let bytes = val.as_bytes();
::base64::engine::general_purpose::STANDARD.encode(bytes)
}
Compiling WinterJS to WASIX was challenging, but completely worth it. Thanks to its WASIX capabilities we can now run any Javascript Service Workers workloads in Wasmer Edge.
We have put together an in depth tutorial on how to use Javascript Service Workers in Wasmer Edge... please check it out!
https://docs.wasmer.io/edge/quickstart/js-wintercg
We believe WinterJS will enable many new use cases. For example, running Service Workers natively in your IoT device (where Node is too heavy to run), or even in your browser.
At Wasmer we are incredibly excited to see how you will use WinterJS.
WinterJS on GitHub: https://github.com/wasmerio/winterjs
Syrus Akbary is an enterpreneur and programmer. Specifically known for his contributions to the field of WebAssembly. He is the Founder and CEO of Wasmer, an innovative company that focuses on creating developer tools and infrastructure for running Wasm
Founder & CEO
Choosing the JS engine
Using SpiderMonkey with mozjs
Using SpiderMokey with spiderfire
Deploying to Wasmer Edge
javascriptWinterJSwasmer edge
Syrus AkbaryNovember 1, 2023
engineeringwasmer edgeedge computing
Syrus AkbaryJune 15, 2023
wasmerwasmer edgerustprojectsedgeweb scraper
RudraAugust 14, 2023