Interesting that asm is opening the door for stuff like this. For compiled node modules with bindings, how does asm compare to binaries? i.e. compiling to asm instead of targeting a particular architecture. Seems like it could be a little neater.
I had a back and forth with some node developers on github a few years ago about this.
Napi (node js's native api) is a much richer API. It allows you talk to V8 & interact with javascript objects directly. So, you can create native javascript objects from native code, attach custom (hidden) properties to existing JS objects, interact with the prototype chain, create promises, make native functions which call C directly, etc. All of this stuff is (currently) way more awkward from wasm. Even just moving data across the wasm-to-javascript divide is a hassle. Wasm compilers solve it for you - but usually by adding a big chunk of generated JS.
Between that and the VM slowdown, the code I've been working with lately, wasm ends up about 3x slower than when I just run it natively.
Wasm code also can't access the native system level stuff - so, no filesystem access, no kernel APIs, etc. Though depending on who you ask, this might be a feature.
But wasm works everywhere - including in the browser, and from Python and Go. With napi you need to compile your code separately for every operating system and CPU architecture pair you want to support. This is a huge pain when publishing an npm module. With wasm its just, compile once, run anywhere. For that reason alone I wouldn't be surprised if wasm became the default recommended way to ship native modules with node soon; at least for modules which aren't super performance sensitive. And there's been talk of exposing the JS GC to wasm for a few years. Hopefully when that stuff lands, it'll get easier to marshal objects across the gap.
> And there's been talk of exposing the JS GC to wasm for a few years. Hopefully when that stuff lands, it'll get easier to marshal objects across the gap.