NAPI-RS
A framework for building compiled Node.js add-ons in Rust via Node-API
README
napi-rs
This project was initialized from xray
A framework for building compiled Node.jsadd-ons in Rustvia Node-API. Website: https://napi.rs
MSRV
Rust1.57.0
| node12 | node14 | node16 | node18 |
| :--- | :--- | :--- | :--- |
| 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| ✓| ✓| ✓| ✓ |
| Linux armv7 android| ✓| ✓| ✓| ✓ |
| FreeBSD x64| ✓| ✓| ✓| ✓ |
This library depends on Node-API and requires Node@10.0.0or 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/JavaScripttoolchain and without involving node-gyp.
Taste
You can start from package-template to play with napi-rs
Define JavaScript functions
- ``` rust
- /// import the preludes
- use napi::bindgen_prelude::*;
- use napi_derive::napi;
- /// module registration is done by the runtime, no need to explicitly do it now.
- #[napi]
- fn fibonacci(n: u32) -> u32 {
- match n {
- 1 | 2 => 1,
- _ => fibonacci(n - 1) + fibonacci(n - 2),
- }
- }
- /// use `Fn`, `FnMut` or `FnOnce` traits to defined JavaScript callbacks
- /// the return type of callbacks can only be `Result`.
- #[napi]
- fn get_cwd<T: Fn(String) -> Result<()>>(callback: T) {
- callback(env::current_dir().unwrap().to_string_lossy().to_string()).unwrap();
- }
- /// or, define the callback signature in where clause
- #[napi]
- fn test_callback<T>(callback: T)
- where T: Fn(String) -> Result<()>
- {}
- /// async fn, require `async` feature enabled.
- /// [dependencies]
- /// napi = {version="2", features=["async"]}
- #[napi]
- async fn read_file_async(path: String) -> Result<Buffer> {
- tokio::fs::read(path)
- .map(|r| match r {
- Ok(content) => Ok(content.into()),
- Err(e) => Err(Error::new(
- Status::GenericFailure,
- format!("failed to read file, {}", e),
- )),
- })
- .await
- }
- ```
more examples at examples
Building
This repository is a Cargocrate. Any napi-based add-on should contain Cargo.tomlto make it a Cargo crate.
In your Cargo.tomlyou need to set the crate-typeto "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 = "2"
- napi-derive = "2"
- [build-dependencies]
- napi-build = "1"
- ```
And create build.rsin your own project:
- ``` rust
- // build.rs
- extern crate napi_build;
- fn main() {
- napi_build::setup();
- }
- ```
So far, the napibuild script has only been tested on macOSLinuxWindows x64 MSVCand FreeBSD.
Install the @napi-rs/clito help you build your Rustcodes and copy Dynamic libfile to .nodefile in case you can requireit 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_namewould be your packagename in your Cargo.toml.
xxx => ./xxx.node
xxx-yyy => ./xxx_yyy.node
You can also copy Dynamic libfile to an appointed location:
- ``` shell
- napi build [--release] ./dll
- napi build [--release] ./artifacts
- ```
There are documents which contains more details about the @napi-rs/cliusage.
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_modulesubdirectory.
To run tests:
- ``` shell
- yarn build:test
- yarn test
- ```
Related projects
neon
node-bindgen
Features table
| Rust Type | Node Type | NAPI Version | Minimal Node version | Enable by | napi | feature |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| u32| Number| 1| v8.0.0| |
| i32/i64| Number| 1| v8.0.0| |
| f64| Number| 1| v8.0.0| |
| bool| Boolean| 1| v8.0.0| |
| String/&'a str| String| 1| v8.0.0| |
| Latin1String| String| 1| v8.0.0| latin1 |
| UTF16String| String| 1| v8.0.0| |
| Object| Object| 1| v8.0.0| |
| serde_json::Map| Object| 1| v8.0.0| serde-json |
| serde_json::Value| any| 1| v8.0.0| serde-json |
| Array| Array| 1| v8.0.0| |
| Vec| Array| 1| v8.0.0| |
| Buffer| Buffer| 1| v8.0.0| |
| External| External| 1| v8.0.0| |
| Null| null| 1| v8.0.0| |
| Undefined/()| undefined| 1| v8.0.0| |
| Result<()>| Error| 1| v8.0.0| || T: Fn(...) -> Result| Function| 1| v8.0.0| |
| Async/Future| Promise| 4| v10.6.0| async |
| AsyncTask| Promise| 1| v8.5.0| |
| JsGlobal| global| 1| v8.0.0| |
| JsSymbol| Symbol| 1| v8.0.0| |
| Int8Array/Uint8Array ...| TypedArray| 1| v8.0.0| |
| JsFunction| threadsafe function| 4| v10.6.0| napi4 |
| BigInt| BigInt| 6| v10.7.0| napi6 |