napi-rs

Stake to support us chat

This project was initialized from xray

A minimal library for building compiled Node.js add-ons in Rust.

Ecosystem

Prisma     swc     Parcel   next.js   nextjs.svg

Platform Support

Lint Linux N-API@3 Linux musl macOS/Windows/Linux x64 Linux-aarch64 Linux-armv7 macOS-Android Windows i686 Windows arm64 FreeBSD

| | node12 | node14 | node16 | | --------------------- | ------ | ------ | ------ | | Windows x64 | ✓ | ✓ | ✓ | | Windows x86 | ✓ | ✓ | ✓ | | Windows arm64 | ✓ | ✓ | ✓ | | macOS x64 | ✓ | ✓ | ✓ | | macOS aarch64 | ✓ | ✓ | ✓ | | Linux x64 gnu | ✓ | ✓ | ✓ | | Linux x64 musl | ✓ | ✓ | ✓ | | Linux aarch64 gnu | ✓ | ✓ | ✓ | | Linux aarch64 musl | ✓ | ✓ | ✓ | | Linux arm gnueabihf | ✓ | ✓ | ✓ | | Linux aarch64 android | ✓ | ✓ | ✓ | | FreeBSD x64 | ✓ | ✓ | ✓ |

This library depends on Node-API and requires Node@10.0.0 or later.

We already have some packages written by napi-rs: node-rs

One nice feature is that this crate allows you to build add-ons purely with the Rust/JavaScript toolchain and without involving node-gyp.

Taste

You can start from package-template to play with napi-rs

Define JavaScript functions

```rust

[js_function(1)] // ------> arguments length

fn fibonacci(ctx: CallContext) -> Result { let n = ctx.get::(0)?.tryinto()?; ctx.env.createint64(fibonacci_native(n)) }

[inline(always)]

fn fibonaccinative(n: i64) -> i64 { match n { 1 | 2 => 1, _ => fibonaccinative(n - 1) + fibonacci_native(n - 2), } } ```

Register module

```rust

[macro_use]

extern crate napi_derive;

use napi::{JsObject, Result};

/// exports is module.exports object in NodeJS

[module_exports]

fn init(mut exports: JsObject) -> Result<()> { exports.createnamedmethod("fibonacci", fibonacci)?; Ok(()) } ```

And you can also create JavaScript value while registering module:

```rust

[macro_use]

extern crate napi_derive;

use napi::{JsObject, Result, Env};

[module_exports]

fn init(mut exports: JsObject, env: Env) -> Result<()> { exports.createnamedmethod("fibonacci", fibonacci)?; exports.setnamedproperty("DEFAULTVALUE", env.createint64(100)?)?; Ok(()) } ```

Building

This repository is a Cargo crate. Any napi-based add-on should contain Cargo.toml to make it a Cargo crate.

In your Cargo.toml you need to set the crate-type to "cdylib" so that cargo builds a C-style shared library that can be dynamically loaded by the Node executable. You'll also need to add this crate as a dependency.

```toml [package] name = "awesome"

[lib] crate-type = ["cdylib"]

[dependencies] napi = "1" napi-derive = "1"

[build-dependencies] napi-build = "1" ```

And create build.rs in your own project:

```rust // build.rs extern crate napi_build;

fn main() { napi_build::setup(); } ```

So far, the napi build script has only been tested on macOS Linux Windows x64 MSVC and FreeBSD.

See the included test_module for an example add-on.

Install the @napi-rs/cli to help you build your Rust codes and copy Dynamic lib file to .node file in case you can require it in your program.

js { "package": "awesome-package", "devDependencies": { "@napi-rs/cli": "^1.0.0" }, "napi": { "name": "jarvis" // <----------- Config the name of native addon, or the napi command will use the name of `Cargo.toml` for the binary file name. }, "scripts": { "build": "napi build --release", "build:debug": "napi build" } }

Then you can require your native binding:

js require('./jarvis.node')

The module_name would be your package name in your Cargo.toml.

xxx => ./xxx.node

xxx-yyy => ./xxx_yyy.node

You can also copy Dynamic lib file to an appointed location:

bash napi build [--release] ./dll napi build [--release] ./artifacts

There are documents which contains more details about the @napi-rs/cli usage.

Testing

Because libraries that depend on this crate must be loaded into a Node executable in order to resolve symbols, all tests are written in JavaScript in the test_module subdirectory.

To run tests:

sh yarn build:test yarn test

Related projects

Features table

Create JavaScript values

| NAPI | NAPI Version | Minimal Node version | Status | | ------------------------------------------------------------------------------------------------------------ | ------------ | -------------------- | ------ | | napicreatearray | 1 | v8.0.0 | ✅ | | napicreatearraywithlength | 1 | v8.0.0 | ✅ | | napicreatearraybuffer | 1 | v8.0.0 | ✅ | | napicreatebuffer | 1 | v8.0.0 | ✅ | | napicreatebuffercopy | 1 | v8.0.0 | ✅ | | napicreatedate | 5 | v11.11.0 | ✅ | | napicreateexternal | 1 | v8.0.0 | ✅ | | napicreateexternalarraybuffer | 1 | v8.0.0 | ✅ | | napicreateexternalbuffer | 1 | v8.0.0 | ✅ | | napicreateobject | 1 | v8.0.0 | ✅ | | napicreatesymbol | 1 | v8.0.0 | ✅ | | napicreatetypedarray | 1 | v8.0.0 | ✅ | | napicreatedataview | 1 | v8.3.0 | ✅ | | napicreateint32 | 1 | v8.4.0 | ✅ | | napicreateuint32 | 1 | v8.4.0 | ✅ | | napicreateint64 | 1 | v8.4.0 | ✅ | | napicreatedouble | 1 | v8.4.0 | ✅ | | napicreatebigintint64 | 6 | v10.7.0 | ✅ | | napicreatebigintuint64 | 6 | v10.7.0 | ✅ | | napicreatebigintwords | 6 | v10.7.0 | ✅ | | napicreatestringlatin1 | 1 | v8.0.0 | ✅ | | napicreatestringutf16 | 1 | v8.0.0 | ✅ | | napicreatestringutf8 | 1 | v8.0.0 | ✅ | | napitype_tag | 8 | v14.8.0, v12.19.0 | ⚠️ |

I have no plan to implement nape_type_tag and related API in napi-rs, because we have implemented a rust replacement in TaggedObject which is more convenient and more compatible.

Functions to convert from Node-API to C types

| NAPI | NAPI Version | Minimal Node Version | Status | | ---------------------------------------------------------------------------------------------------- | ------------ | -------------------- | ------ | | napigetarraylength | 1 | v8.0.0 | ✅ | | napigetarraybufferinfo | 1 | v8.0.0 | ✅ | | napigetbufferinfo | 1 | v8.0.0 | ✅ | | napigetprototype | 1 | v8.0.0 | ✅ | | napigettypedarrayinfo | 1 | v8.0.0 | ✅ | | napigetdataviewinfo | 1 | v8.3.0 | ✅ | | napigetdatevalue | 5 | v11.11.0 | ✅ | | napigetvaluebool | 1 | v8.0.0 | ✅ | | napigetvaluedouble | 1 | v8.0.0 | ✅ | | napigetvaluebigintint64 | 6 | v10.7.0 | ✅ | | napigetvaluebigintuint64 | 6 | v10.7.0 | ✅ | | napigetvaluebigintwords | 6 | v10.7.0 | ✅ | | napigetvalueexternal | 1 | v8.0.0 | ✅ | | napigetvalueint32 | 1 | v8.0.0 | ✅ | | napigetvalueint64 | 1 | v8.0.0 | ✅ | | napigetvaluestringlatin1 | 1 | v8.0.0 | ✅ | | napigetvaluestringutf8 | 1 | v8.0.0 | ✅ | | napigetvaluestringutf16 | 1 | v8.0.0 | ✅ | | napigetvalueuint32 | 1 | v8.0.0 | ✅ | | napigetboolean | 1 | v8.0.0 | ✅ | | napigetglobal | 1 | v8.0.0 | ✅ | | napigetnull | 1 | v8.0.0 | ✅ | | napigetundefined | 1 | v8.0.0 | ✅ |

Working with JavaScript Values and Abstract Operations

| NAPI | NAPI Version | Minimal Node Version | Status | | ---------------------------------------------------------------------------------------------------- | ------------ | -------------------- | ------ | | napicoercetobool | 1 | v8.0.0 | ✅ | | napicoercetonumber | 1 | v8.0.0 | ✅ | | napicoercetoobject | 1 | v8.0.0 | ✅ | | napicoercetostring | 1 | v8.0.0 | ✅ | | napitypeof | 1 | v8.0.0 | ✅ | | napiinstanceof | 1 | v8.0.0 | ✅ | | napiisarray | 1 | v8.0.0 | ✅ | | napiisarraybuffer | 1 | v8.0.0 | ✅ | | napiisbuffer | 1 | v8.0.0 | ✅ | | napiisdate | 1 | v8.0.0 | ✅ | | napiiserror | 1 | v8.0.0 | ✅ | | napiistypedarray | 1 | v8.0.0 | ✅ | | napiisdataview | 1 | v8.3.0 | ✅ | | napistrictequals | 1 | v8.0.0 | ✅ | | napidetacharraybuffer | 7 | v13.3.0 | ✅ | | napiisdetachedarraybuffer | 7 | v13.3.0 | ✅ | | napiobjectfreeze | 8 | v14.14.0, v12.20.0 | ✅ | | napiobject_seal | 8 | v14.14.0, v12.20.0 | ✅ |