yarn global add @napi-rs/cli
# or
npm install -g @napi-rs/cli
# or
pnpm add -g @napi-rs/cli
The name filed in package.json
.
Choose targets you want to support
Platforms you want support to.
Generate GitHub actions config for you.
Here it is recommended to distribute your package under npm scope because @napi-rs/cli
by default appends the different platform suffixes to the npm package name as the package name for the different platform binary distribution. Using npm scope will reduce the case of package name was taken.
For example if you want publish package @cool/core
, with the macOS x64
, Windows x64
and Linux aarch64
supported, @napi-rs/cli
will create and publish four packages for you:
@cool/core
includes just JavaScript
codes, which actually load the native binary from per platforms.
@cool/core-darwin-x64
for macOS x64
platform.
@cool/core-win32-x64
for Windows x64
platform.
@cool/core-linux-arm64-gnu
for Linux aarch64
platform.
In every platform binary package, there are cpu
and os
fields in there package.json
:
{
"name" : " @cool/core-darwin-x64" ,
"version" : " 1.0.0" ,
"os" : [" darwin" ],
"cpu" : [" x64" ]
}
And @cool/core
using these native packages as optionalDependencies
:
{
"name" : " @cool/core" ,
"version" : " 1.0.0" ,
"optionalDependencies" : {
"@cool/core-darwin-x64" : " ^1.0.0" ,
"@cool/core-win32-x64" : " ^1.0.0" ,
"@cool/core-linux-arm64" : " ^1.0.0"
}
}
And your index.js
in @cool/core
will be this:
const { existsSync, readFileSync } = require ( 'fs' )
const { join } = require ( 'path' )
const { platform, arch } = process
let nativeBinding = null
let localFileExisted = false
let isMusl = false
let loadError = null
switch ( platform ) {
case 'darwin' :
switch ( arch ) {
case 'x64' :
localFileExisted = existsSync ( join ( __dirname , 'core.darwin-x64.node' ) )
try {
if ( localFileExisted ) {
nativeBinding = require ( './core.darwin-x64.node' )
} else {
nativeBinding = require ( '@cool/core-darwin-x64' )
}
} catch ( e ) {
loadError = e
}
break
case 'arm64' :
localFileExisted = existsSync ( join ( __dirname , 'core.darwin-arm64.node' ) )
try {
if ( localFileExisted ) {
nativeBinding = require ( './core.darwin-arm64.node' )
} else {
nativeBinding = require ( '@cool/core-darwin-arm64' )
}
} catch ( e ) {
loadError = e
}
break
default :
throw new Error ( `Unsupported architecture on macOS: ${ arch } ` )
}
break
// ...
default :
throw new Error ( `Unsupported OS: ${ platform } , architecture: ${ arch } ` )
}
if ( ! nativeBinding ) {
if ( loadError ) {
throw loadError
}
throw new Error ( `Failed to load native binding` )
}
const { plus100 } = nativeBinding
module . exports . plus100 = plus100
The generated index.js
file will help you to load the right binary file wherever you are. And the index.js
handle two cases:
Package installed in users node_modules
To load the correct binary, the index.js
function tries to load all possible packages for that platform (there may be multiple possible binary packages for a given system and CPU architecture), for example, on the Linux x64
platform, index.js
tries to load @cool/core-linux-x64-gnu
and @cool/core-linux-x64-musl
. The package @cool/core-linux-x64-gnu
will be loaded if the user is using an operating system like Ubuntu
Debian
with gnu libc
pre-installed. And if the user is using an operating system like Alpine
with musl libc
pre-installed, then @cool/core-linux-x64-musl
will be loaded.
The build
command in package.json in the project generated by the @napi-rs/cli
new command will generate the binary dynamic link library compiled from the Rust
code into the current directory for debugging purposes. index.js
will also try to load the corresponding binary from the current directory in this case. Again using Linux x64
as an example, the index.js
function will try to load the core.linux-x64-gnu.node
and core.linux-x64-musl.node
files in turn.
If your IDE refuses to autocomplete/autosuggest code when using the #[napi]
macro, you can use the following setting to fix this:
For vscode in settings.json
:
{
"rust-analyzer.procMacro.ignored" : { "napi-derive" : [" napi" ] }
}
For Neovim.
['rust-analyzer' ] = {
procMacro = {
ignored = {
['napi-derive'] = { 'napi' },
},
},
},
This problem emits the following error in rust-analyser:
[ERROR proc_macro_api::msg] proc-macro tried to print : `napi` macro expand failed.
Start from GitHub template project
Go to GitHub template project
Click Use this template .
Clone your project.
Run yarn install
to install dependencies.
Run npx napi rename
command under the project folder to rename your package.