Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use WebAssembly from node.js?

I am currently working on a personal Node.js (>=8.0.0) project which requires me to call C subroutines (to improve execution time). I am trying to use WebAssembly to do this since I need my final code to be compatible when opened in a browser.

I have used Emscripten to compile C code into WebAssembly, and do not know how to proceed after this.

Any help in the right direction would be great. Thanks!

like image 491
Cheran Avatar asked Jul 18 '18 13:07

Cheran


People also ask

Does node js support Wasm?

WebAssembly is a high-performance assembly-like language. It can be compiled from C/C++, Rust, and AssemblyScript, among other languages. Right now, it is supported by Chrome, Safari, Edge, Firefox, and Node. js!

Is Rust faster than Nodejs?

js vs Rust. After optimizations, the Rust FaaS runtime ended up being >70% faster while using >90% less memory than our reference Node. js implementation.

Can you use WebAssembly without JavaScript?

wasm binary. By itself, WebAssembly cannot currently directly access the DOM; it can only call JavaScript, passing in integer and floating point primitive data types. Thus, to access any Web API, WebAssembly needs to call out to JavaScript, which then makes the Web API call.


2 Answers

You can build a .wasm file (standalone) without JS glue file. Someone has answered the similar question.

Create a test.c file:

int add(int a, int b) {
  return a + b;
}

Build the standalone .wasm file:

emcc test.c -O2 -s WASM=1 -s SIDE_MODULE=1 -o test.wasm

Use the .wasm file in Node.js app:

const util = require('util');
const fs = require('fs');
var source = fs.readFileSync('./test.wasm');
const env = {
    memoryBase: 0,
    tableBase: 0,
    memory: new WebAssembly.Memory({
      initial: 256
    }),
    table: new WebAssembly.Table({
      initial: 0,
      element: 'anyfunc'
    })
  }

var typedArray = new Uint8Array(source);

WebAssembly.instantiate(typedArray, {
  env: env
}).then(result => {
  console.log(util.inspect(result, true, 0));
  console.log(result.instance.exports._add(9, 9));
}).catch(e => {
  // error caught
  console.log(e);
});

The key part is the second parameter of WebAssembly.instantiate(). Without it, you will get the error message:

TypeError: WebAssembly Instantiation: Imports argument must be present and must be an object at at process._tickCallback (internal/process/next_tick.js:188:7) at Function.Module.runMain (module.js:695:11) at startup (bootstrap_node.js:191:16) at bootstrap_node.js:612:3

like image 131
yushulx Avatar answered Oct 14 '22 12:10

yushulx


Thanks @sven. ( translate only )

test.c:

#include <emscripten/emscripten.h>

int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
    return a + b;
}

compiling:

emcc test.c -O2 -s WASM=1 -s SIDE_MODULE=1 -o test.wasm

test.js:

const util = require('util');
const fs = require('fs');
var source = fs.readFileSync('./test.wasm');
const env = {
  __memory_base: 0,
  tableBase: 0,
  memory: new WebAssembly.Memory({
    initial: 256
  }),
  table: new WebAssembly.Table({
    initial: 0,
    element: 'anyfunc'
  })
}

var typedArray = new Uint8Array(source);

WebAssembly.instantiate(typedArray, {
  env: env
}).then(result => {
  console.log(util.inspect(result, true, 0));
  console.log(result.instance.exports._add(10, 9));
}).catch(e => {
  // error caught
  console.log(e);
});
like image 45
Helmut Kemper Avatar answered Oct 14 '22 11:10

Helmut Kemper