Neon Enables Embedding Rust Code in Node.js Apps

Neon is a library and toolchain that makes it possible to create native Node modules using Rust. This is similar to what is possible with C and C++, but with the additional benefits brought by Rust safety guarantees.

Neon strives to make creating Node.js module straightforward. Once you have installed the Neon package from npm and the Rust toolchain, you can use neon new <project-name> to create a skeleton Node module that embeds a Cargo.toml file and a Rust source file including a sample hello function:

 <project-name>/  ├── .git ignore  ├──  ├── lib/  │   └── index.js  ├── native/  │   ├── Cargo.toml  │   └── src/  │       └──  └── package.json  

You can add any Rust dependencies you need to Cargo.toml and layout your code as you prefer. You can export a Rust function so it can be used in a Node program in two steps. First, you register the function using:

 register_module!(mut m, {      m.export_function("myFunction", thread_count)  });  

Then, you export it from lib/index.js:

 const addon = require('../native');  module.exports = addon.myFunction;  

When your code is ready, you can build the Node module with:

 neon build --release  

As straightforward as this appears, you should anyway pay special attention to behaving as a good citizen in the Node environment. In particular, any Rust function you export should be of a specific type:

 fn add1(mut cx: FunctionContext) -> JsResult<JsNumber> {  ...  }  

Here, FunctionContext gives you access to the Node caller environment, including its arguments list. Similarly, an exported function should return a JsResult, an option type which specifies the function returns a given type or throws a JavaScript exception. For example, you can access a specific argument using the syntax:

 let x = cx.argument::<JsNumber>(0)?.value();  

To return a value from an exported function, you should properly cast it to the expected value. For example, if your function returns a number, you would use the Rust as f64 casting operator when returning it:

   Ok(cx.number(num_cpus::get() as f64))  

Among the advantages of building a native Node module is the possibility of executing asynchronous background tasks. Neon uses N-API's microtasks API to that aim and relies on callbacks and promises on the JavaScript side to control async task execution.

As a last note, Neon can be used also with Electron apps. This requires at the moment the use of an intermediate tool, electron-build-env, to build any Neon dependencies used in an Electron app. The Neon team is working on support for electron-rebuild, which will streamline this process and enable to use Neon dependencies just like any other dependencies in an Electron project.