Getting started
High-performance Rust functions in Node.js
This page is outdated. Please visit here to see how to run Rust functions in Node.js.
There are great use cases for WebAssembly on the server-side, especially for AI, blockchain, and big data applications. In this tutorial, I will show you how to incorporate WebAssembly functions, written in Rust, into Node.js applications on the server. This approach combines Rust's performance, WebAssembly's security and portability, and JavaScript's ease-of-use. A typical Rust + Node.js hybrid app works like this.
The host application is a Node.js web application written in JavaScript. It makes WebAssembly function calls.
The WebAssembly bytecode program is written in Rust. It runs inside the SSVM, and is called from the Node.js web application.
The source code of the tutorial is here. If you just want to try it out, you can fork this repository and use the VSCode IDE to open it.
Prerequisites
Since we are building Rust functions to run in Node.js, make sure that you have Rust and Node.js installed on your computer.
Setup
We use the Second State Virtual Machine (SSVM) , an open source WebAssembly runtime optimized for server-side applications, together with Node.js.
The ssvm and ssvmup npm modules install the Second State Virtual Machine (SSVM) into Node.js as a native addon, and provides the necessary compiler tools. Learn more about the ssvmup tool.
WebAssembly program in Rust
In this example, our Rust program appends the input string after “hello”. Below is the content of the Rust program src/lib.rs
. You can define multiple external functions in this library file, and all of them will be available to the host JavaScript app via WebAssembly. Just remember to annotate each function with #[wasm_bindgen]
so that ssvmup knows to generate the correct JavaScript to Rust interface for it when you build it.
Next, you can compile the Rust source code into WebAssembly bytecode and generate the accompanying JavaScript module for the Node.js host environment.
The result are files in the pkg/
directory. the .wasm
file is the WebAssembly bytecode program, and the .js
files are for the JavaScript module.
The Node.js host application
Next, go to the node
folder and examine the JavaScript program app.js
. With the generated hello_lib.js
module, it is very easy to write JavaScript to call WebAssembly functions. Below is the node application app.js
. It simply imports the say()
function from the generated module. The node application takes the name
parameter from incoming an HTTP GET request, and responds with “hello name
”.
Start the Node.js application server as follows.
Then, you can test it.
More complex examples
Besides passing string values between Rust and JavaScript, the ssvmup tool supports the following data types.
Rust call parameters can be any combo of
i32
,String
,&str
,Vec<u8>
, and&[u8]
Return value can be
i32
orString
orVec<u8>
For complex data types, such as structs, you could use JSON strings to pass data.
With JSON support, you can call Rust functions with any number of input parameters and return any number of return values of any type.
The Rust program src/lib.rs
in the functions example demonstrates how to pass in call arguments in various supported types, and return values.
Perhaps the most interesting is the create_line()
function. It takes two JSON strings, each representing a Point
struct, and returns a JSON string representing a Line
struct. Notice that both the Point
and Line
structs are annotated with Serialize
and Deserialize
so that the Rust compiler automatically generates necessary code to support their conversion to and from JSON strings.
Next, let's examine the JavaScript program app.js
. It shows how to call the Rust functions. As you can see String
and &str
are simply strings in JavaScript, i32
are numbers, and Vec<u8>
or &[8]
are JavaScript Uint8Array
. JavaScript objects need to go through JSON.stringify()
or JSON.parse()
before being passed into or returned from Rust functions.
After running ssvmup to build the Rust library, running app.js
in Node.js environment produces the following output.
What’s next?
Now we have seen a very simple example to call a Rust function from JavaScript in a Node.js application. In the next article, we will discuss how to pass arbitrary arguments from a JavaScript program to Rust.
Last updated