🕸️ Using rust modules in JavaScript/Web Development (Part 3/ 3) [NodeJS]

Atul
Atul
Apr 3, 2018 · 3 min read

Please read the Part 1 of the series here :

For this part of the series, you can safely skip Part 2, but if you are interested :

*Prerequisite:

Setup the rust project from Part 1 of this post. Follow the Setting up the rust project part of the post.

Hence you should have a simple calculator project in rust ready before continuing.

Lets Begin

We will do the following:

  1. Compile our rust module as a dynamic library.
  2. Use node-ffi (Node.js Foreign Function Interface) to use the functions exported from rust module.

Generating a dynamic library file

To generate a dynamic library file from a rust file run the compile command with the following arguments

rustc --crate-type=cdylib src/lib.rs -o libweb.dylib

PS: This is a slightly different command as compared to the one we used in Part 1

Note: If you prefer using cargo to do the build:

  1. Modify the Cargo.toml file and add the following
[package]
...
...
[lib]
crate-type = ["cdylib"]
[dependencies]
...
...

2. Remove the file src/main.rs otherwise this will not compile since we changed the crate-type to cdylib.

3. run cargo build --release

You should get an output like this:

➜  web git:(master) ✗ > cargo build --release
Compiling web v0.1.0 (file:///Users/atulr/Projects/Hobby/rust/projects/web)
Finished release [optimized] target(s) in 0.28 secs

4. You should find the libweb.dylib file at web/target/release/libweb.dylib

Note: Keep in mind this is a dylib file as compared to wasm file from part 1

We are now half way through the process !! 🌮

Use node-ffi (Node.js Foreign Function Interface) to use the functions exported from rust module.

node-ffi is a Node.js addon for loading and calling dynamic libraries using pure JavaScript. It can be used to create bindings to native libraries without writing any C++ code.

In short we can use node-ffi to call the public exported functions from the rust module.

To do this lets create a new node project.

  1. mkdir noderust && cd noderust— create a directory for our node project
  2. Now create the following file structure:
noderust
├── index.js
├── package.json
└── yarn.lock

3. yarn add ffi or npm install --save ffi — add the ffi dependency.

4. Your package.json should look something like this:

{
"name": "noderust",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"ffi": "^2.2.0"
}
}

5. Now add the following code to your index.js file.

const ffi = require('ffi');
const libPath = 'path/to/libweb.dylib';
const libWeb = ffi.Library(libPath, {
'add': [ 'int32', [ 'int32', 'int32' ] ],
'subtract': [ 'int32', [ 'int32', 'int32' ] ],
'multiply': [ 'int32', [ 'int32', 'int32' ] ]
});
const { add, subtract, multiply } = libWeb;
console.log('4 + 2 = ', add(4, 2));
console.log('4 - 2 = ', subtract(4, 2));
console.log('4 * 2 = ', multiply(4, 2));

Lets understand this code line by line.

const libPath = 'path/to/libweb.dylib';

This is the path to compiled dynamic library file of the rust code that we generated earlier.

const libWeb = ffi.Library(libPath, {
'add': [ 'int32', [ 'int32', 'int32' ] ],
'subtract': [ 'int32', [ 'int32', 'int32' ] ],
'multiply': [ 'int32', [ 'int32', 'int32' ] ]
});

Here the signature of the ff.Library function looks something like this:

ffi.Library(libraryFile, {
functionSymbol: [ returnType, [ arg1Type, arg2Type, ... ]],
...
...
});

Now since our add function in rust has the following signature

fn add(first: i32, second:i32) -> i32 

the corresponding format for add would be:

'add': [ 'int32', [ 'int32', 'int32' ] ],

Similarly, subtract and multiply have similar configurations.

You can check the complete list of types here: https://github.com/TooTallNate/ref/wiki/Known-%22types%22

That’s it, lets run it!

npm start

If everything went well, you should see:

➜  noderust git:(master) ✗ > yarn start
yarn run v1.5.1
$ node index.js
4 + 2 = 6
4 - 2 = 2
4 * 2 = 8
✨ Done in 0.20s.

Hurray !! We are now running rust module directly from NodeJS. 🎉🌮🧞‍♂️

PS: You can also use a very nice library neon https://github.com/neon-bindings/neon to achieve the same. But the purpose of the post was to show you a way to integrate rust with node (other than web-assembly way).

Hope this was fun ! 🌮🍺🎉

Source Code:

References:

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store