### Install Dependencies with Yarn Source: https://github.com/napi-rs/website/blob/main/README.md Use this command to install all necessary project dependencies before starting development. Ensure you have Yarn installed. ```sh yarn install ``` -------------------------------- ### Install Dependencies and Build Native Package Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/simple-package.en.mdx After creating the project, install dependencies using your package manager (e.g., yarn) and then build the native package with `yarn build`. ```bash cd cool yarn install ``` ```bash yarn build yarn run v1.22.17 $ napi build --platform --release Updating crates.io index Downloaded proc-macro2 v1.0.34 Downloaded once_cell v1.9.0 Downloaded napi v2.0.0-beta.7 Downloaded 3 crates (129.4 KB) in 2.35s Compiling proc-macro2 v1.0.34 Compiling unicode-xid v0.2.2 Compiling memchr v2.4.1 Compiling syn v1.0.82 Compiling regex-syntax v0.6.25 Compiling convert_case v0.4.0 Compiling once_cell v1.9.0 Compiling napi-build v1.2.0 Compiling napi-sys v2.1.0 Compiling napi-rs_cool v0.0.0 (/cool) Compiling quote v1.0.10 Compiling aho-corasick v0.7.18 Compiling regex v1.5.4 Compiling napi-derive-backend v1.0.17 Compiling ctor v0.1.21 Compiling napi-derive v2.0.0-beta.5 Compiling napi v2.0.0-beta.7 Finished release [optimized] target(s) in 37.11s ✨ Done in 37.80s. ``` -------------------------------- ### Start Development Server with Yarn Source: https://github.com/napi-rs/website/blob/main/README.md Run this command to start the local development server. The website will be available at http://localhost:3000. ```sh yarn dev ``` -------------------------------- ### Install @napi-rs/cli Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/getting-started.en.mdx Install the napi-rs CLI tool globally using yarn, npm, or pnpm. ```bash yarn global add @napi-rs/cli # or npm install -g @napi-rs/cli # or pnpm add -g @napi-rs/cli ``` -------------------------------- ### Platform-Specific package.json Configuration Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/getting-started.en.mdx Example package.json for a platform-specific binary distribution, defining 'os' and 'cpu' fields. ```json { "name": "@cool/core-darwin-x64", "version": "1.0.0", "os": ["darwin"], "cpu": ["x64"] } ``` -------------------------------- ### Main Package.json with Optional Dependencies Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/getting-started.en.mdx Example package.json for a main package that lists platform-specific native packages as optional dependencies. ```json { "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" } } ``` -------------------------------- ### Example: Custom Tokio Runtime with `#[napi_derive::module_init]` Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/module-init.en.mdx Demonstrates setting up a custom Tokio runtime for a native module. This initialization runs once per process, making it suitable for global async runtimes. ```rust use napi::bindgen_prelude::create_custom_tokio_runtime; #[napi_derive::module_init] fn init() { let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .thread_name("my-native-module") .build() .unwrap(); create_custom_tokio_runtime(rt); } ``` -------------------------------- ### Module Initialization Function (Feudal Style) Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/history.en.mdx An example of a module initialization function written in the 'Feudal style' for older Node.js versions. ```cpp // Feudal style void Init(Local exports) { NODE_SET_METHOD(exports, "echo", Echo); } ``` -------------------------------- ### Module Initialization Function (NAN Style) Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/history.en.mdx An example of a module initialization function written in the NAN style, demonstrating the use of Nan::Set and Nan::New. ```cpp // NAN style NAN_MODULE_INIT(Init) { Nan::Set( target, Nan::New("echo").ToLocalChecked(), Nan::GetFunction(Nan::New(Echo)).ToLocalChecked()); } ``` -------------------------------- ### Install wasm32 Packages with Yarn v1 Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/webassembly.en.mdx For Yarn v1, use the '--ignore-engines' flag to install wasm32 packages, as it lacks other effective methods. ```bash yarn install --ignore-engines ``` -------------------------------- ### Unsafe External Buffer Example in NAPI-RS Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/typed-array.en.mdx Provides an example of using `BufferSlice::from_external` with manual memory management. It highlights the critical need to forget the original `Vec` to prevent double-free and properly reconstruct it in the finalize callback for deallocation. ```rust use napi::bindgen_prelude::*; use napi_derive::napi; #[napi] pub fn unsafe_external_example(env: &Env) -> Result> { let mut data = vec![1u8, 2, 3, 4, 5]; let ptr = data.as_mut_ptr(); let len = data.len(); // ⚠️ CRITICAL: Must forget the Vec to prevent double-free std::mem::forget(data); unsafe { BufferSlice::from_external(env, ptr, len, ptr, move |_, ptr| { // ✅ Properly reconstruct and drop the Vec std::mem::drop(Vec::from_raw_parts(ptr, len, len)); // Vec automatically deallocates when dropped }) } } ``` -------------------------------- ### Combine `module_init` and `module_exports` Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/module-init.en.mdx Demonstrates using both `#[napi_derive::module_init]` for global setup (like a Tokio runtime) and `#[napi(module_exports)]` for per-thread export customization. The `module_init` function runs once at load time, while `module_exports` runs per thread context. ```rust use napi::bindgen_prelude::*; // Runs once at module load - setup tokio runtime #[cfg(not(target_family = "wasm"))] #[napi_derive::module_init] fn setup_runtime() { let rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() .unwrap(); create_custom_tokio_runtime(rt); } // Runs per thread - customize exports #[napi(module_exports)] pub fn customize_exports(mut exports: Object) -> Result<()> { exports.set_named_property("THREAD_SAFE_SYMBOL", Symbol::for_desc("THREAD_SAFE"))?; Ok(()) } // Regular export via #[napi] #[napi] pub async fn do_async_work() -> String { // This uses the tokio runtime set up in module_init tokio::time::sleep(std::time::Duration::from_millis(100)).await; "done".to_string() } ``` -------------------------------- ### Install wasm32 Packages with npm Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/webassembly.en.mdx Use the '--cpu=wasm32' flag with npm version 10.2.0 or later to manually install wasm32 architecture packages. ```bash npm install --cpu=wasm32 ``` -------------------------------- ### Programmatic Build with @napi-rs/cli Source: https://github.com/napi-rs/website/blob/main/pages/blog/announce-v3.en.mdx Demonstrates how to use the NapiCli class from '@napi-rs/cli' to programmatically build native Node.js addons. This example shows how to configure build options such as release mode, features, ESM output, and platform-specific builds. ```APIDOC ## Programmatic Build with `@napi-rs/cli` API You can now easily integrate the **NAPI-RS** tools into your JavaScript infra: ```ts // Programmatically import { NapiCli } from '@napi-rs/cli' const cli = new NapiCli() const { task, abort } = await cli.build({ release: true, features: ['allocator-api'], esm: true, platform: true, }) const outputs = await task ``` All napi commands have corresponding APIs, you can visit [`cli`](/docs/cli/build) to learn more. ``` -------------------------------- ### Package.json for Platform-Specific Native Addons Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/release.en.mdx This `package.json` configuration demonstrates how to use `optionalDependencies` along with `os` and `cpu` fields to automatically select the correct native addon package for the user's system during installation. ```json { "name": "@node-rs/bcrypt", "version": "0.5.0", "os": ["linux", "win32", "darwin"], "cpu": ["x64"], "optionalDependencies": { "@node-rs/bcrypt-darwin": "^0.5.0", "@node-rs/bcrypt-linux": "^0.5.0", "@node-rs/bcrypt-win32": "^0.5.0" } } ``` ```json { "name": "@node-rs/bcrypt-darwin", "version": "0.5.0", "os": ["darwin"], "cpu": ["x64"] } ``` ```json { "name": "@node-rs/bcrypt-linux", "version": "0.5.0", "os": ["linux"], "cpu": ["x64"] } ``` ```json { "name": "@node-rs/bcrypt-win32", "version": "0.5.0", "os": ["win32"], "cpu": ["x64"] } ``` -------------------------------- ### Transform Image with WebAssembly Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/webassembly.en.mdx Demonstrates how to use the `@napi-rs/image` package to transform an image fetched from a URL into WebP format using WebAssembly. This example requires fetching image data and then processing it with the Transformer class. ```typescript import { Transformer } from '@napi-rs/image' export async function transform() { const imageBytes = await fetch('https://images-assets.nasa.gov/image/carina_nebula/carina_nebula~orig.png') .then(res => res.arrayBuffer()) const transformer = new Transformer(imageBytes) const webp = await transformer.toWebp() } ``` -------------------------------- ### Programmatic NAPI-RS Build with CLI API Source: https://github.com/napi-rs/website/blob/main/pages/blog/announce-v3.en.mdx Use the `@napi-rs/cli` programmatically to build native Node.js addons. This example demonstrates how to initiate a release build with specific features and ESM output. ```typescript import { NapiCli } from '@napi-rs/cli' const cli = new NapiCli() const { task, abort } = await cli.build({ release: true, features: ['allocator-api'], esm: true, platform: true, }) const outputs = await task ``` -------------------------------- ### N-API Build Process Control Flow Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/programmatic-api.en.mdx Illustrates the multi-phase build process for N-API Rust projects, including setup, build, and type generation. It highlights key steps like reading package.json, spawning Cargo, and generating type definitions. ```text ┌─────────────────────────────────────────────────────────────────────────┐ │ SETUP PHASE │ ├─────────────────────────────────────────────────────────────────────────┤ │ 1. Read package.json for napi config │ │ 2. Get target triple (from cli flag) (e.g.,'x86_64-unknown-linux-gnu') │ │ 3. parseTriple() → get platformArchABI for binding filename │ │ 4. mkdir(typeDefDir) → create directory for type definitions │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ BUILD PHASE │ ├─────────────────────────────────────────────────────────────────────────┤ │ 5. spawn('cargo', ['build', '--release']) │ │ └─ env: { NAPI_TYPE_DEF_TMP_FOLDER: typeDefDir } │ │ ▲ │ │ └─ This env var tells napi-derive where to write type defs │ │ │ │ 6. rm(old binding) → Remove old .node file (prevents macOS segfault) │ │ 7. copyFile(libfoo.so → customized.{platform}.node) │ │ 8. Stream stdout/stderr from cargo │ │ 9. await cargo completion │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────┐ │ TYPE GENERATION PHASE │ ├─────────────────────────────────────────────────────────────────────────┤ │ 10. generateTypeDef({ typeDefDir, cwd }) │ │ └─ Reads intermediate .json files from typeDefDir │ │ └─ Returns { dts: string, exports: string[] } │ │ │ │ 11. writeFile('customized.d.ts', dts) │ │ │ │ 12. writeJsBinding({ platform, binaryName, idents: exports, ... }) │ │ └─ Generates JS loader that imports the .node file │ └─────────────────────────────────────────────────────────────────────────┘ │ ▼ ┌───────────┐ │ DONE │ │ │ │ Output: │ │ • .node │ │ • .d.ts │ │ • .js │ └───────────┘ ``` -------------------------------- ### Example Usage of TypedArray Functions Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Demonstrates how to call the `convertU32Array` and `mutateTypedArray` functions from JavaScript, showing the input and expected output or side effects. ```javascript import { convertU32Array, mutateTypedArray } from './index.js' convertU32Array(new Uint32Array([1, 2, 3, 4, 5])) // [1, 2, 3, 4, 5] mutateTypedArray(new Float32Array([1, 2, 3, 4, 5])) // Float32Array(5) [ 2, 4, 6, 8, 10 ] ``` -------------------------------- ### JavaScript Index File for Loading Native Bindings Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/getting-started.en.mdx The index.js file dynamically loads the correct native binary based on the current platform and architecture. It handles both local .node files and packages installed via npm. ```javascript 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 ``` -------------------------------- ### JavaScript Example of Non-Writable Property Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/class.en.mdx Demonstrates attempting to assign a new function to the `getNum` property of a `QueryEngine` instance, which will result in a TypeError because the property is not writable. ```javascript import { QueryEngine } from './index.js' const qe = new QueryEngine() qe.getNum = function () {} // TypeError: Cannot assign to read only property 'getNum' of object '#' ``` -------------------------------- ### Get UV Event Loop Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Gets a pointer to the underlying libuv event loop. Requires the `napi2` feature. ```rust pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> ``` -------------------------------- ### Initialize Git Repository Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/simple-package.en.mdx Initialize a Git repository, add a remote origin, commit changes, and push to GitHub. This is necessary for publishing with GitHub Actions. ```bash git init git remote add origin git@github.com/yourname/cool.git git add . git commit -m "Init" git push ``` -------------------------------- ### Get Array Length in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Use the `arr.len()` method to get the length of a JavaScript Array passed into a Rust function. Note that JavaScript Arrays can hold mixed types, while Rust `Vec` requires a single type. ```rust #[napi] pub fn arr_len(arr: Array) -> u32 { arr.len() } ``` -------------------------------- ### get_node_version Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Gets the Node.js version information. ```APIDOC ## `get_node_version` Gets the Node.js version information. ### Signature ```rust pub fn get_node_version(&self) -> Result ``` ``` -------------------------------- ### get_napi_version Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Gets the N-API version (`process.versions.napi`). ```APIDOC ## `get_napi_version` Gets the N-API version (`process.versions.napi`). ### Signature ```rust pub fn get_napi_version(&self) -> Result ``` ``` -------------------------------- ### Create New N-API Project Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/simple-package.en.mdx Use `napi new` to initiate a new N-API project. You will be prompted for the package name and directory name. ```bash napi new ? Package name: (The name field in your package.json) ``` ```bash napi new ? Package name: (The name field in your package.json) @napi-rs/cool ? Dir name: (cool) ``` ```bash napi new ? Package name: (The name field in your package.json) @napi-rs/cool ? Dir name: cool ? Choose targets you want to support (Press to select, to toggle all, to invert selection, and to proceed) ❯ ◯ aarch64-apple-darwin ◯ aarch64-linux-android ◯ aarch64-unknown-linux-gnu ◯ aarch64-unknown-linux-musl ◯ aarch64-pc-windows-msvc ◯ armv7-unknown-linux-gnueabihf ◉ x86_64-apple-darwin (Move up and down to reveal more choices) ``` ```bash napi new ? Package name: (The name field in your package.json) @napi-rs/cool ? Dir name: cool ? Choose targets you want to support aarch64-apple-darwin, aarch64-linux-android, aarch64-unknown-linux-gnu , aarch64-unknown-linux-musl, aarch64-pc-windows-msvc, armv7-unknown-linux-gnueabihf, x86_64-apple-darwin, x86_64-pc-windows-msvc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, x86_64-unknown-freebsd, i686-p c-windows-msvc, armv7-linux-androideabi ? Enable github actions? (Y/n) ``` ```bash napi new ? Package name: (The name field in your package.json) @napi-rs/cool ? Dir name: cool ? Choose targets you want to support aarch64-apple-darwin, aarch64-linux-android, aarch64-unknown-linux-gnu , aarch64-unknown-linux-musl, aarch64-pc-windows-msvc, armv7-unknown-linux-gnueabihf, x86_64-apple-darwin, x86_64-pc-windows-msvc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl, x86_64-unknown-freebsd, i686-p c-windows-msvc, armv7-linux-androideabi ? Enable github actions? Yes Writing Cargo.toml Writing .npmignore Writing build.rs Writing package.json Writing src/lib.rs Writing .github/workflows/CI.yml Writing .cargo/config.toml Writing rustfmt.toml ``` -------------------------------- ### get_uv_event_loop Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Gets a pointer to the underlying libuv event loop. Requires the `napi2` feature. ```APIDOC ## get_uv_event_loop ### Description Gets a pointer to the underlying libuv event loop. ### Method (Implicitly a method on an environment object) ### Signature ```rust pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> ``` ### Requirements Requires `napi2` feature. ``` -------------------------------- ### Get Node.js Version Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Obtain Node.js version information using the `get_node_version` method. ```rust pub fn get_node_version(&self) -> Result ``` -------------------------------- ### Create a New napi-rs Project Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/getting-started.en.mdx Use the napi-rs CLI to create a new native Node.js addon project. This command will prompt for project details like package name, target platforms, and GitHub Actions configuration. ```bash napi new ``` -------------------------------- ### Get N-API Version Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Retrieve the N-API version of the current Node.js environment using `get_napi_version`. ```rust pub fn get_napi_version(&self) -> Result ``` -------------------------------- ### Build Project via CLI Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/build.en.mdx Use the `napi build` command in your terminal to build your NAPI-RS project. Options can be appended after the command. ```sh napi build [--options] ``` -------------------------------- ### Get Instance Data Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Retrieves data previously associated with the currently running Agent. Requires the `napi6` feature. ```rust pub fn get_instance_data(&self) -> Result> where T: 'static, ``` -------------------------------- ### Get Last Node-API Error Information Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Retrieve detailed information about the most recent Node-API error using `get_last_error_info`. ```rust pub fn get_last_error_info(&self) -> Result ``` -------------------------------- ### Typical Bundler Plugin API with Callbacks Source: https://github.com/napi-rs/website/blob/main/pages/blog/function-and-callbacks.en.mdx Illustrates how bundler plugins use callbacks for different build phases like file transformation, progress reporting, and error handling. Requires a bundler instance with a plugin API. ```javascript myBundler.plugin({ name: 'my-plugin', setup(build) { // Transform files during compilation build.onLoad({ filter: /\.tsx?$/ }, async (args) => { const content = await transformTypeScript(args.path); return { contents: content }; }); // Report build progress build.onProgress((percentage, message) => { console.log(`${percentage}% - ${message}`); }); // Handle compilation errors build.onError((error) => { notifyDevelopers(error); }); } }); ``` -------------------------------- ### Configure Yarn for wasm32 Architecture Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/webassembly.en.mdx Use the 'supportedArchitectures' setting in '.yarnrc.yml' to allow Yarn v4 to install wasm32 packages. ```yaml supportedArchitectures: cpu: - current - wasm32 ``` -------------------------------- ### Post-process Build Outputs with oxfmt Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/programmatic-api.en.mdx This script demonstrates how to use the programmatic API to build project outputs and then format the generated JavaScript and TypeScript files using oxfmt. It iterates through the build outputs, formats non-native addon files, and writes the formatted code back to the output path. ```typescript import { readFile, writeFile } from 'node:fs/promises' import { NapiCli, createBuildCommand } from '@napi-rs/cli' import { format, type FormatOptions } from 'oxfmt' import oxfmtConfig from './.oxfmtrc.json' with { type: 'json' } const buildCommand = createBuildCommand(process.argv.slice(2)) const cli = new NapiCli() const buildOptions = buildCommand.getOptions() const { task } = await cli.build(buildOptions) const outputs = await task for (const output of outputs) { if (output.kind !== 'node') { const { code } = await format(output.path, await readFile(output.path, 'utf-8'), oxfmtConfig as FormatOptions) await writeFile(output.path, code) } } ``` -------------------------------- ### FunctionRef Limitation Example Source: https://github.com/napi-rs/website/blob/main/pages/blog/function-and-callbacks.en.mdx Demonstrates a scenario where FunctionRef cannot be used in a regular std::thread::spawn due to the absence of Env. ```rust use napi::bindgen_prelude::*; #[napi] pub fn store_callback(callback: Function) -> Result<()> { let callback_ref = callback.create_ref()?; // ❌ THIS WON'T WORK - No Env in regular thread std::thread::spawn(move || { // Error: Can't borrow_back without Env! // callback_ref.borrow_back(???)?; }); Ok(()) } ``` -------------------------------- ### CLI Usage Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/universalize.en.mdx Command-line interface for the universalize command. ```APIDOC ## CLI Usage ```sh napi universalize [--options] ``` ``` -------------------------------- ### Get Module File Name Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/env.en.mdx Retrieves the file path of the currently running JS module as a URL. Requires the `napi9` feature. ```rust pub fn get_module_file_name(&self) -> Result ``` -------------------------------- ### Get Undefined Value in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Represents `undefined` in JavaScript. Default return or empty tuple `()` are `undefined` after converted into JS value. ```rust #[napi] pub fn get_undefined() -> Undefined { () } ``` ```rust // default return or empty tuple `()` are `undefined` after converted into JS value. #[napi] pub fn log(n: u32) { println!("{}", n); } ``` -------------------------------- ### JavaScript Test File for Native Addon Source: https://github.com/napi-rs/website/blob/main/pages/docs/introduction/simple-package.en.mdx Create a JavaScript file to import and test the native `sum` function. Ensure the import path correctly points to the generated JavaScript binding file. ```javascript import { sum } from './index.js' console.log('From native', sum(40, 2)) ``` -------------------------------- ### Run Post-processing Script Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/programmatic-api.en.mdx Execute the build script with the same arguments that would be passed to the `napi build` CLI command. This allows for consistent build and post-processing behavior. ```bash node ./build.ts --release --platform ``` -------------------------------- ### Abort AsyncTask with AbortController Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/async-task.en.mdx Demonstrates how to abort an AsyncTask from JavaScript using an AbortController. If the task has not started, it will be aborted immediately and reject with AbortError. ```javascript import { asyncFib } from './index.js' const controller = new AbortController() asyncFib(20, controller.signal).catch((e) => { console.error(e) // Error: AbortError }) controller.abort() ``` -------------------------------- ### Configure PrepublishOnly Script Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/pre-publish.en.mdx Add this script to your package.json to automatically run the napi pre-publish command before publishing your package to npm. ```json "scripts": { "prepublishOnly": "napi prepublish -t npm" } ``` -------------------------------- ### Check Boolean Value in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Returns a boolean value, representing JavaScript's `Boolean` type. This is a simple example of boolean conversion. ```rust #[napi] pub fn is_good() -> bool { true } ``` -------------------------------- ### Options Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/universalize.en.mdx Available options for the universalize command. ```APIDOC ## Options | Options | CLI Options | type | required | default | description | | --------------- | ------------------- | ------ | -------- | -------------- | ------------------------------------------------------------------------------------------------------------------ | | | --help,-h | | | | get help | | cwd | --cwd | string | false | process.cwd() | The working directory of where napi command will be executed in, all other paths options are relative to this path | | configPath | --config-path,-c | string | false | | Path to napi config json file | | packageJsonPath | --package-json-path | string | false | package.json | Path to package.json | | outputDir | --output-dir,-o | string | false | ./ | Path to the folder where all built .node files put, same as --output-dir of build command | ``` -------------------------------- ### Create External Buffer Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/external.en.mdx Creates an External object holding a Buffer of a specified length. This is a basic example of creating an External object in Rust. ```rust use napi::bindgen_prelude::*; use napi_derive::napi; #[napi] pub fn create_source_map(length: u32) -> External { External::new(vec![0; length as usize].into()) } ``` -------------------------------- ### Module Initialization Function (N-API Style) Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/history.en.mdx This is how a module initialization function is written in the N-API style, using napi_property_descriptor for defining exports. ```cpp void Init(napi_env env, napi_value exports, napi_value module, void* priv) { napi_status status; // Description constructs for setting exports napi_property_descriptor desc = { "echo", 0, Echo, 0, 0, 0, napi_default, 0 }; // set "echo" into `module.exports` status = napi_define_properties(env, exports, 1, &desc); } ``` -------------------------------- ### Attempting to Modify Non-Writable Property Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/class.cn.mdx Shows a JavaScript example attempting to reassign a non-writable property, resulting in a TypeError. This illustrates the effect of `writable = false`. ```javascript import { QueryEngine } from './index.js' const qe = new QueryEngine() qe.getNum = function () {} // TypeError: Cannot assign to read only property 'getNum' of object '#' ``` -------------------------------- ### CLI Usage for napi new Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/new.en.mdx Use this command in your terminal to create a new NAPI-RS project at the specified path with optional configurations. ```bash napi new [--options] ``` -------------------------------- ### Basic `#[napi_derive::module_init]` Signature Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/module-init.en.mdx This macro marks a function to run once when the native module is first loaded. The function must accept no arguments and return no value. ```rust #[napi_derive::module_init] fn init() { // initialization code } ``` -------------------------------- ### Handle Buffer in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Demonstrates receiving a `Buffer` from JavaScript and converting it into a `Vec`, and also creating a `Buffer` from a file read operation. ```rust #[napi] pub fn with_buffer(buf: Buffer) { let buf: Vec = buf.into(); // do something } ``` ```rust #[napi] pub fn read_buffer(file: String) -> Buffer { Buffer::from(std::fs::read(file).unwrap()) } ``` -------------------------------- ### Get Null Value in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Represents `null` value in JavaScript. Handles environment variable retrieval, returning `Some(value)` on success or `None` if the variable is not set. ```rust #[napi] pub fn get_null() -> Null { Null } ``` ```rust #[napi] pub fn get_env(env: String) -> Option { match std::env::var(env) { Ok(val) => Some(val), Err(e) => None, } } ``` -------------------------------- ### Node.js DLOpen Function Implementation Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/native-module.en.mdx Examines the C++ implementation of `process.dlopen()` in Node.js v10.23.0, illustrating the steps involved in loading and initializing a native module. ```cpp // DLOpen is process.dlopen(module, filename, flags). void DLOpen(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); auto context = env->context(); Local module; Local exports; Local exports_v; // initialize `module`, `module.exports` values if (!args[0]->ToObject(context).ToLocal(&module) || // this line is equal to `exports = module.exports` !module->Get(context, env->exports_string()).ToLocal(&exports_v) || !exports_v->ToObject(context).ToLocal(&exports)) { return; // Exception pending. } node::Utf8Value filename(env->isolate(), args[1]); // Cast DLib dlib(*filename, flags); bool is_opened = dlib.Open(); node_module* const mp = static_cast( uv_key_get(&thread_local_modpending)); uv_key_set(&thread_local_modpending, nullptr); ... // transfer the handle in dynamic lib to the `mp` mp->nm_dso_handle = dlib.handle_; mp->nm_link = modlist_addon; modlist_addon = mp; if (mp->nm_context_register_func != nullptr) { mp->nm_context_register_func(exports, module, context, mp->nm_priv); } else if (mp->nm_register_func != nullptr) { mp->nm_register_func(exports, module, mp->nm_priv); } else { dlib.Close(); env->ThrowError("Module has no declared entry point."); return; } } ``` -------------------------------- ### CLI Usage for Universalize Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/universalize.en.mdx Use the `napi universalize` command with optional flags to combine binaries. Refer to the options table for available flags. ```bash # CLI napi universalize [--options] ``` -------------------------------- ### Call Promise Finally Callback from TypeScript Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/reference.en.mdx Example of how to invoke the `promiseFinallyCallback` function from TypeScript, demonstrating its usage with a simple Promise and a console log in the finally block. ```typescript import { promiseFinallyCallback } from './index.js' promiseFinallyCallback(Promise.resolve(), () => { console.log('finally') }) ``` -------------------------------- ### Set WASI SDK Path for C/C++ Dependencies Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/webassembly.en.mdx Download wasi-sdk and set the WASI_SDK_PATH environment variable to the SDK folder to build WebAssembly packages with C/C++ dependencies. ```bash # on macOS aarch64 wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-arm64-macos.tar.gz tar -xvf wasi-sdk-25.0-arm64-macos.tar.gz export WASI_SDK_PATH="$(pwd)/wasi-sdk-25.0-arm64-macos" ``` -------------------------------- ### Rust Enum to JavaScript Object Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/enum.en.mdx Rust enums are converted to plain JavaScript objects. This example shows a basic Rust enum and its corresponding TypeScript definition. ```rust #[napi] pub enum Kind { Duck, Dog, Cat, } ``` ```typescript export const enum Kind { Duck, Dog, Cat, } ``` -------------------------------- ### Build Project Programmatically Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/build.en.mdx Import and instantiate `NapiCli` to build your NAPI-RS project using code. Pass build options as an object to the `build` method. ```typescript import { NapiCli } from '@napi-rs/cli' new NapiCli().build({ // options }) ``` -------------------------------- ### Call Rust async function and await Promise in JavaScript Source: https://github.com/napi-rs/website/blob/main/pages/blog/announce-v2.en.mdx Example of calling the `async_plus_100` Rust function from JavaScript, passing a JavaScript Promise and logging the resolved value. ```javascript import { asyncPlus100 } from './index.js' const fx = 20 const result = await asyncPlus100( new Promise((resolve) => { setTimeout(() => resolve(fx), 50) }), ) console.log(result) // 120 ``` -------------------------------- ### Get Vector Length in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Calculate the length of a Rust `Vec` and return it as a `u32`. This function expects a `Vec` as input, which corresponds to a JavaScript Array of numbers. ```rust #[napi] pub fn vec_len(nums: Vec) -> u32 { u32::try_from(nums.len()).unwrap() } ``` -------------------------------- ### Create Npm Dirs CLI Usage Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/create-npm-dirs.en.mdx Use this command in your terminal to create npm package directories. Options can be appended to customize the process. ```bash # CLI napi create-npm-dirs [--options] ``` -------------------------------- ### CLI Usage of Pre Publish Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/pre-publish.en.mdx Use this command in your terminal to execute the pre-publish process. ```sh napi pre-publish [--options] ``` -------------------------------- ### Convert BufferSlice to Owned Buffer for Async Use Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/typed-array.en.mdx Converts a BufferSlice to an owned Buffer, enabling its use in asynchronous operations. The example demonstrates summing the elements of the buffer asynchronously. ```rust use napi::bindgen_prelude::*; use napi_derive::napi; #[napi] pub fn buffer_slice_to_buffer(env: &Env, slice: BufferSlice) -> Result> { // Convert BufferSlice to owned Buffer for async usage let buffer = slice.into_buffer(env)?; AsyncBlockBuilder::new(async move { // use the buffer in async context Ok(buffer.iter().sum()) }) .build(env) } ``` ```typescript export declare function bufferSliceToBuffer(slice: Buffer): Promise ``` ```typescript import { bufferSliceToBuffer } from './index.js' const slice = Buffer.from([1, 2, 3, 4, 5]) const result = await bufferSliceToBuffer(slice) console.log(result) // 15 ``` -------------------------------- ### Access Raw Object in Class Methods Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/inject-this.en.md In class methods, you can access the raw `Object` value of the `Class` instance using `This`. This allows you to get properties from the JavaScript object directly. ```rust use napi::{bindgen_prelude::*}; use napi_derive::napi; #[napi] pub struct QueryEngine {} #[napi] impl QueryEngine { #[napi(constructor)] pub fn new() -> Result { Ok(Self {}) } #[napi] pub fn get_ref_count(&self, this: This) -> Result> { this.get::("refCount") } } ``` ```js import { QueryEngine } from './index.js' const qe = new QueryEngine() qe.refCount = 3 console.log(qe.getRefCount()) // 3 ``` -------------------------------- ### Download All Artifacts with actions/download-artifact Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/artifacts.en.mdx Use this GitHub Action to download all built native addon artifacts into a specified directory. This is typically done in a CI/CD pipeline before further processing. ```yaml - name: Download all artifacts uses: actions/download-artifact@v2 with: path: artifacts ``` -------------------------------- ### Weak ThreadsafeFunction Example Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/threadsafe-function.en.mdx Configure ThreadsafeFunction with `Weak` set to `true` to prevent the Node.js event loop from staying alive. This is useful when the thread calling the function should not keep the process running. ```rust use std::{sync::Arc, thread}; use napi::{ bindgen_prelude::*, threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode}, }; use napi_derive::napi; #[napi] pub fn call_threadsafe_function( tsfn: Arc>, ) -> Result<()> { for n in 0..100 { let tsfn = tsfn.clone(); thread::spawn(move || { tsfn.call(n, ThreadsafeFunctionCallMode::Blocking); }); } Ok(()) } ``` ```typescript import { callThreadsafeFunction } from './index.js' // log nothing because the event loop exit immediately callThreadsafeFunction((err, n) => { if (err) { console.error(err) } else { console.log(n) } }) ``` -------------------------------- ### Programmatic Usage of Pre Publish Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/pre-publish.en.mdx Instantiate NapiCli and call the prePublish method to run the process from your code. ```typescript // Programmatically import { NapiCli } from '@napi-rs/cli' new NapiCli().prePublish({ // options }) ``` -------------------------------- ### Function Declaration Comparison (0.10.x vs 6.x) Source: https://github.com/napi-rs/website/blob/main/pages/docs/deep-dive/history.en.mdx Illustrates the difference in function declaration syntax for the Echo function between Node.js versions 0.10.x and 6.x. ```cpp Handle Echo(const Arguments& args); // 0.10.x void Echo(FunctionCallbackInfo& args); // 6.x ``` -------------------------------- ### Broken Timer Example (Invalid Callback) Source: https://github.com/napi-rs/website/blob/main/pages/blog/function-and-callbacks.en.mdx Demonstrates an incorrect way to use callbacks in asynchronous operations. Storing a raw `Function` and calling it after the Rust function returns will cause a crash. ```rust // ❌ THIS WON'T WORK - Function becomes invalid after return #[napi] pub fn broken_timer(callback: Function) -> Result<()> { std::thread::spawn(move || { std::thread::sleep(std::time::Duration::from_secs(1)); // ERROR: callback is no longer valid here! // The JavaScript function was cleaned up when broken_timer returned callback.call("Too late!".to_string()); // This will crash! }); Ok(()) // Function returns, callback becomes invalid } ``` -------------------------------- ### Game Engine Callbacks for Updates and Collisions Source: https://github.com/napi-rs/website/blob/main/pages/blog/function-and-callbacks.en.mdx Provides examples of game engine callbacks for handling frame updates with delta time and managing collision events between game objects. These are performance-critical. ```javascript gameEngine.onUpdate((deltaTime) => { updatePhysics(deltaTime); renderFrame(); }); gameEngine.onCollision((objectA, objectB) => { handleCollisionPhysics(objectA, objectB); }); ``` -------------------------------- ### Update napi build command: --cargo-cwd to --manifest-path Source: https://github.com/napi-rs/website/blob/main/pages/docs/more/v2-v3-migration-guide.en.mdx The `--cargo-cwd` flag has been removed from the `napi build` command. Use `--manifest-path` to specify the path to the `Cargo.toml` file. ```bash napi build --manifest-path ./crates/napi/Cargo.toml ``` -------------------------------- ### Handle Promise with `then` in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/promise.en.mdx Use `PromiseRaw<'env, T>` to call JavaScript Promise methods like `then` within a synchronous Rust context. This example adds 100 to the resolved value of the incoming promise. ```rust use napi::bindgen_prelude::*; use napi_derive::napi; #[napi] pub fn promise_callback(promise: PromiseRaw) -> Result> { promise.then(|ctx| Ok(ctx.value + 100)) } ``` -------------------------------- ### Rust Functions to Accept Classes Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/class.en.mdx Rust functions demonstrating how to accept `QueryEngine` class instances as immutable or mutable references. Ownership is transferred to JavaScript. ```rust pub fn accept_class(engine: &QueryEngine) { // ... } pub fn accept_class_mut(engine: &mut QueryEngine) { // ... } ``` -------------------------------- ### Instantiate and Use NapiCli Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/programmatic-api.en.mdx Instantiate the NapiCli class to access its methods for building, collecting artifacts, creating new projects, and more. Available methods include build, artifacts, new, createNpmDirs, prePublish, rename, universalize, and version. ```typescript import { NapiCli } from '@napi-rs/cli' const cli = new NapiCli() // Available methods: cli.build(options) // Build the project cli.artifacts(options) // Collect artifacts from CI cli.new(options) // Create new project cli.createNpmDirs(options)// Create npm package directories cli.prePublish(options) // Prepare for publishing cli.rename(options) // Rename project cli.universalize(options) // Create universal binaries cli.version(options) // Update versions ``` -------------------------------- ### Greet with String in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Takes a `String` from JavaScript and returns a formatted greeting `String`. This showcases basic string manipulation and conversion. ```rust #[napi] pub fn greet(name: String) -> String { format!("greeting, {}", name) } ``` -------------------------------- ### Abort a Build Process Source: https://github.com/napi-rs/website/blob/main/pages/docs/cli/programmatic-api.en.mdx The build() method returns an abort function that can be used to cancel the build process. This example demonstrates how to handle SIGINT signals to abort the build cleanly and exit the process. ```typescript const { task, abort } = await cli.build(options) // Handle SIGINT to abort cleanly process.on('SIGINT', () => { abort() process.exit(1) }) const outputs = await task ``` -------------------------------- ### Creating Copied Buffers in NAPI-RS Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/typed-array.en.mdx Illustrates how to create a BufferSlice by copying data from a byte slice. Note that this method incurs a performance overhead due to data copying. ```rust use napi::bindgen_prelude::*; use napi_derive::napi; #[napi] pub fn create_copied_buffer(env: &Env) -> Result> { let data = b"Hello, World!"; BufferSlice::copy_from(env, &data) } ``` -------------------------------- ### Creating Engine Instance in TypeScript Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/understanding-lifetime.en.mdx Shows how to instantiate the Rust-defined 'Engine' class from TypeScript. ```typescript const engine = new Engine() ``` -------------------------------- ### Manipulate JavaScript Objects in Rust Source: https://github.com/napi-rs/website/blob/main/pages/docs/concepts/values.en.mdx Provides functions to interact with JavaScript objects, including getting keys, logging specific fields, and creating new objects. Note that Object conversions have higher costs. ```rust #[napi] pub fn keys(obj: Object) -> Vec { Object::keys(&obj).unwrap() } ``` ```rust #[napi] pub fn log_string_field(obj: Object, field: String) { println!("{:?}", obj.get::::(field.as_ref())); } ``` ```rust #[napi] pub fn create_obj(env: Env) -> Object { let mut obj = env.create_object().unwrap(); obj.set("test", 1).unwrap(); obj } ```