Hello World!

Examples

This guide will walk you through writing, building, and running your first Neon project. We'll try to walk you through each step carefully, but if you want to skip ahead, you can always go straight to the full demo in the examples repository.

Our first project will be a tiny module that returns a number indicating how much hardware multithreading the current machine supports. If you're not familiar with multithreading, don't panic! We'll be using Sean McArthur's num_cpus library to do all the heavy lifting for us, and we'll just return the number it gives us.

But even this simple example already demonstrates some of Neon's usefulness: Rust's crate ecosystem is younger than npm but growing quickly and already full of useful and unique libraries. A library like num_cpus could be useful, for example, as a hint for tuning the size of a Web Worker pool in an Electron app.

Creating a New Project

The first thing we have to do is create our new thread-count Neon project:

neon new thread-count

This will ask us a series of questions similar to the ones asked by npm new. When it completes, the tool will have created a thread-count directory with the following layout:

thread-count/
├── .gitignore
├── README.md
├── lib/
│ └── index.js
├── native/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
└── package.json

The first thing to notice about this layout is that a Neon project is a Node package. In other words, the way to think of a Neon project is:

Node on the outside, Rust on the inside.

The front-end of a Neon package is a pure JavaScript module (lib/index.js, by default), and the back-end is a native library implemented as a Rust crate. The Rust crate lives in the native/ subdirectory of the project.

Building and Running

We haven't yet implemented anything, but just to see that neon new produced a complete, minimal Neon project, let's try building it:

cd thread-count
neon build --release

The build process generates a handful of files that you don't need to work with directly:

  • native/index.node: the native module itself, which is loaded by lib/index.js.
  • native/target and native/artifacts.json: cached build results, which makes rebuilds faster.

An easy way to clean up build artifacts is to run:

neon clean

Once we've built the project, we can try running it:

node
> require('.')
hello node
{}

Adding a Rust Dependency

Let's add a Rust dependency on the num_cpus crate. In native/Cargo.toml, under the [dependencies] section, add the following line:

num_cpus = "1.4.0"

This tells Cargo, Rust's build tool, to fetch a version of the num_cpus crate that is semver-compatible with 1.4.0. (The package.json equivalent would be "num_cpus": "^1.4.0".)

Implementing our Function

Next we can replace the sample hello function that was generated by neon new with the function we actually want. Instead of returning a string, our function should return a JavaScript number. So we'll use cx.number() helper. Since cx.number() expects a Rust f64 (i.e., a 64-bit floating-point number), and num_cpus::get() returns a usize (i.e., a pointer-sized integer), we'll use Rust'sas operator to cast to convert the integer to floating-point:

use num_cpus;
use neon::prelude::*;
fn thread_count(mut cx: FunctionContext) -> JsResult<JsNumber> {
Ok(cx.number(num_cpus::get() as f64))
}

A few more things to note about this code:

  • The cx argument to thread_count: this contains information about the function call, such as the arguments and the value of this.
  • The JsResult output type: this is a Rust Result type that indicates whether the function returned (Ok) or threw a JavaScript exception (Err). You can learn more in the Errors docs. It also tracks the lifetime of the returned handle.
  • The cx.number() function tells the JavaScript garbage collector that we need to keep the value we allocate alive long enough to return it to the caller of thread_count.

Finally, we'll modify the code that neon new created for us to set up the module exports with this function instead of the initial "hello world" function it created for us:

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

This tells Neon to initialize the module when it's first loaded by creating a JavaScript function implemented with the thread_count function we defined above and exporting it as a module property named "threadCount".

You can see the full lib.rs file in the examples repository.

Exporting our Function

Now that the Rust code is implemented, all we have left to do is export it from the project's public module in lib/index.js. The native module exported a threadCount property, so we'll just make that function our entire public module:

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

Try it Out!

Now we should be able to rebuild the project with neon build --release again:

neon build --release

This will create a release build for us. Assuming we didn't make any mistakes, we can test out our new Neon module at the Node console from the root of our project directory:

node
> var threadCount = require('.')
> threadCount()
4

Keep in mind that the result of calling threadCount() will vary based on the machine you run this demo on—by design!