DEV Community


Posted on • Updated on

Using WebAssembly for a NodeJS Native Addon

Recently I have released an npm @gfx/zopfli, which is a JavaScript binding to google/zopfli, as a drop-in replacement to node-zopfli.

I have a story for this package: it is built with Emscripten into WebAssembly.

WebAssembly is a portable executable format for the web browsers, but it is not only for the web but usable for nodejs native addons. That is, the package includes pre-built executable binary in wasm. No compiler is required to install it. No node-pre-gyp magic is required (in fact node-zopfli has problems with node-pre-gyp pierreinglebert/node-zopfli#87). Even Windows users can use it just by npm install @gfx/zofpli (or yarnpkg add @gfx/zopfli).

You might be worried about wasm performance, but I think it is already production-ready, although it is slower than native code.

Here is a benchmark result in the repo on NodejS 8.9.1 (see benchmark/random-bytes.js for the code):

payload size: 1

universal-zopfli x 106 ops/sec ±0.79% (80 runs sampled)
node-zopfli x 201 ops/sec ±1.99% (82 runs sampled)

payload size: 1024

universal-zopfli x 1.37 ops/sec ±12.99% (11 runs sampled)
node-zopfli x 4.62 ops/sec ±3.34% (27 runs sampled)

payload size: 1038336

universal-zopfli x 0.26 ops/sec ±6.91% (6 runs sampled)
node-zopfli x 0.39 ops/sec ±1.35% (6 runs sampled)

The speed (ops/sec) of universal-zopfli (i.e. in wasm) is about 30% - 70% of node-zopfli (i.e. in native code). It is good enough for production if you use @gfx/zopfli as a Zlib alternative in compression-webpack-plugin. And fortunately, the current state of WebAssembly implementation in NodeJS/V8 is just an MVP! It should be getting better in performance.

Development of nodejs native addon with Emscripten is difficult for now, but I believe most of NodeJS native addons which do not use systemcalls, including nodejs standard libraries such as zlib, can be replaced with wasm because of its portability.

Discussion (0)