{"id":13478273,"url":"https://github.com/infinyon/node-bindgen","last_synced_at":"2025-05-14T06:13:35.345Z","repository":{"id":37178112,"uuid":"238088141","full_name":"infinyon/node-bindgen","owner":"infinyon","description":"Easy way to write Node.js module using Rust","archived":false,"fork":false,"pushed_at":"2025-01-13T13:14:53.000Z","size":853,"stargazers_count":555,"open_issues_count":45,"forks_count":44,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-13T07:19:31.696Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/infinyon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-04T00:06:44.000Z","updated_at":"2025-04-03T06:36:37.000Z","dependencies_parsed_at":"2024-01-17T10:33:06.397Z","dependency_job_id":"63ae3b45-06d3-4f75-b4fe-032298ae6260","html_url":"https://github.com/infinyon/node-bindgen","commit_stats":{"total_commits":125,"total_committers":23,"mean_commits":5.434782608695652,"dds":0.648,"last_synced_commit":"97357ba1beda7e027f40ffbbd529f653ea54781b"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinyon%2Fnode-bindgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinyon%2Fnode-bindgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinyon%2Fnode-bindgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/infinyon%2Fnode-bindgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/infinyon","download_url":"https://codeload.github.com/infinyon/node-bindgen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248675972,"owners_count":21143846,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T16:01:54.871Z","updated_at":"2025-04-13T07:20:05.867Z","avatar_url":"https://github.com/infinyon.png","language":"Rust","readme":"\n\u003ch1 align=\"center\"\u003enode-bindgen\u003c/h1\u003e\n\u003cdiv align=\"center\"\u003e\n \u003cstrong\u003e\n   Easy way to write native Node.js module using idiomatic Rust\n \u003c/strong\u003e\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n   \u003c!-- CI status --\u003e\n  \u003ca href=\"https://github.com/infinyon/node-bindgen/actions\"\u003e\n    \u003cimg src=\"https://github.com/infinyon/node-bindgen/workflows/CI/badge.svg\"\n      alt=\"CI Status\" /\u003e\n  \u003c/a\u003e\n  \u003c!-- Crates version --\u003e\n  \u003ca href=\"https://crates.io/crates/node-bindgen\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/v/node-bindgen?style=flat-square\"\n    alt=\"Crates.io version\" /\u003e\n  \u003c/a\u003e\n  \u003c!-- Downloads --\u003e\n  \u003ca href=\"https://crates.io/crates/node-bindgen\"\u003e\n    \u003cimg src=\"https://img.shields.io/crates/d/node-bindgen.svg?style=flat-square\"\n      alt=\"Download\" /\u003e\n  \u003c/a\u003e\n  \u003c!-- docs.rs docs --\u003e\n  \u003ca href=\"https://docs.rs/node-bindgen\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square\"\n      alt=\"docs.rs docs\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca href=\"https://discord.gg/V5MhmEq\"\u003e\n    \u003cimg src=\"https://img.shields.io/discord/695712741381636168.svg?logo=discord\u0026style=flat-square\"\n      alt=\"chat\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\n## Features\n\n- __Easy:__ Just write idiomatic Rust code, node-bindgen take care of generating Node.js FFI wrapper codes.\n- __Safe:__ Node.js arguments are checked automatically based on Rust types.\n- __Async:__ Support Async Rust.  Async codes are translated into Node.js promises.\n- __Class:__ Rust struct can be accessed using Node.js classes.\n- __Stream:__ Implement Node.js stream using Rust\n- __N-API:__ Use Node.js N-API, which means you don't have to recompile your module.\n\n# Compatibility with Node.js version\n\nThis project uses the v8 of Node N-API.  Please see following [compatibility](https://nodejs.org/api/n-api.html#n_api_n_api_version_matrix) matrix.\n\nFollowing OS are supported:\n* Linux\n* MacOs\n* Windows\n\n\n\n# Why node-bindgen?\n\nWriting native node-js requires lots of boilerplate code.  Node-bindgen generates external \"C\" glue code from rust code, including native module registration.  node-bindgen make it writing node-js module easy and fun.\n\n\n# Getting started\n\n## CLI Installation\n\nInstall nj-cli command line, which will be used to generate the native library.\n\n```sh\ncargo install nj-cli\n```\n\nThis is a one time step.\n\n## Configuring Cargo.toml\n\nAdd two dependencies to your projects' ```Cargo.toml```.\n\nAdd ```node-bindgen``` as a regular dependency (as below):\n```toml\n[dependencies]\nnode-bindgen = { version = \"6.0\" }\n```\n\nThen add ```node-bindgen```'s procedure macro to your build-dependencies as below:\n```toml\n[build-dependencies]\nnode-bindgen = { version = \"6.0\", default-features = false, features = [\"build\"] }\n```\n\nThen update crate type to ```cdylib``` to generate node.js compatible native module:\n```toml\n[lib]\ncrate-type = [\"cdylib\"]\n```\n\nFinally, add ```build.rs``` at the top of the project with following content:\n\n```rust,ignore\nfn main() {\n    node_bindgen::build::configure();\n}\n```\n\n\n# Example\n\nHere is a function that adds two numbers.  Note that you don't need to worry about JS conversion.\n\n\n```rust,ignore\n\nuse node_bindgen::derive::node_bindgen;\n\n/// add two integer\n#[node_bindgen]\nfn sum(first: i32, second: i32) -\u003e i32 {\n    first + second\n}\n\n```\n\n## Building native library\n\nTo build node.js library, using ```nj-cli``` to build:\n\n```sh\nnj-cli build\n```\n\nThis will generate Node.js module in \"./dist\" folder.\n\nTo build a release version:\n```sh\nnj-cli build --release\n```\n\n## Watching `./src` for Changes\n\nWhile developing your native module, you may want to watch for file changes and run a command when a change occurs, for example `cargo check` or `cargo build`.\n\nFor this, we can use `nj-cli watch`.\n\n`nj-cli watch` installs \u003csmall\u003e[if it does not exist]\u003c/small\u003e and passes arguments to [`cargo watch`](https://crates.io/crates/cargo-watch). By default, `nj-cli watch` will run `cargo check` against your `./src` files.\n\nTo see all available methods for `nj-cli watch`, run the following command:\n\n\u003e `nj-cli watch -- --help`\n\n## Using in Node.js\n\nThen in the Node.js, rust function can be invoked as normal node.js function:\n\n```js\n$ node\nWelcome to Node.js v18.18.0.\nType \".help\" for more information.\n\u003e let addon = require('./dist');\nundefined\n\u003e addon.sum(2,3)\n5\n\u003e\n```\n\n\n# Features\n\n## Function name or method can be renamed instead of default mapping\n\n```rust,ignore\n#[node_bindgen(name=\"multiply\")]\nfn mul(first: i32,second: i32) -\u003e i32 {\n    first * second\n}\n```\n\nRust function mul is re-mapped as ```multiply```\n\n## Optional argument\n\nArgument can be skipped if it is marked as optional\n```rust,ignore\n#[node_bindgen]\nfn sum(first: i32, second: Option\u003ci32\u003e) -\u003e i32 {\n    first + second.unwrap_or(0)\n}\n```\nThen sum can be invoked as\n```sum(10)``` or ```sum(10,20)```\n\n\n##  Callback\n\nJS callback are mapped as Rust closure.\n\n```rust,ignore\n#[node_bindgen]\nfn hello\u003cF: Fn(String)\u003e(first: f64, second: F) {\n\n    let msg = format!(\"argument is: {}\", first);\n\n    second(msg);\n}\n```\n\nfrom node:\n\n```js\nlet addon = require('./dist');\n\naddon.hello(2,function(msg){\n  assert.equal(msg,\"argument is: 2\");\n  console.log(msg);  // print out argument is 2\n});\n```\n\nCallback are supported in Async rust as well.\n\n## Support for Async Rust\n\nAsync rust function is mapped to Node.js promise.\n\n```rust,ignore\n\nuse std::time::Duration;\nuse flv_future_aio::time::sleep;\nuse node_bindgen::derive::node_bindgen;\n\n\n#[node_bindgen]\nasync fn hello(arg: f64) -\u003e f64 {\n    println!(\"sleeping\");\n    sleep(Duration::from_secs(1)).await;\n    println!(\"woke and adding 10.0\");\n    arg + 10.0\n}\n```\n\n```js\nlet addon = require('./dist');\n\naddon.hello(5).then((val) =\u003e {\n  console.log(\"future value is %s\",val);\n});\n\n```\n\n## Struct serialization\n\nStructs, including generic structs, can have have the to-JS conversion boilerplate autogenerated.\nJust apply the `node_bindgen` macro to your struct:\n\n```rust,ignore\n#[node_bindgen]\nstruct MyJson {\n    some_name: String,\n    a_number: i64\n}\n\n#[node_bindgen]\nfn my_json() -\u003e MyJson {\n    MyJson {\n        some_name: \"John\".to_owned(),\n        a_number: 1337\n    }\n}\n```\n\n```js\nlet addon = require('./dist');\nassert.deepStrictEqual(addon.my_json(), {\n    someName: \"John\",\n    aNumber: 1337\n});\n```\n\nNote that the fields must implement\n`node_bindgen::core::TryIntoJs` themselves.\nAny references must also implement `Clone`.\nField names will be converted to camelCase.\n\n## Enums\n\nEnums will also have their JS representation autogenerated with the help of `node_bindgen`:\n\n```rust,ignore\n#[node_bindgen]\nenum ErrorType {\n    WithMessage(String, usize),\n    WithFields {\n        val: usize\n    },\n    UnitErrorType\n}\n\n#[node_bindgen]\nfn with_message() -\u003e ErrorType {\n    ErrorType::WithMessage(\"test\".to_owned(), 321)\n}\n\n#[node_bindgen]\nfn with_fields() -\u003e ErrorType {\n    ErrorType::WithFields {\n        val: 123\n    }\n}\n\n#[node_bindgen]\nfn with_unit() -\u003e ErrorType {\n    ErrorType::UnitErrorType\n}\n```\n\n```js\nassert.deepStrictEqual(addon.withMessage(), {\n    withMessage: [\"test\", 321n]\n});\nassert.deepStrictEqual(addon.withFields(), {\n    withFields: {\n        val: 123n\n    }\n});\nassert.deepStrictEqual(addon.withUnit(), \"UnitErrorType\")\n```\n\nTuple variants will be converted into lists, struct variants converted to objects, and unit variants converted into strings matching the variant's name in PascalCase.\nGenerics and references are supported, with the same caveats as for structs.\n\n## JavaScript class\n\nJavaScript class is supported.\n\n```rust,ignore\n\nstruct MyClass {\n    val: f64,\n}\n\n\n#[node_bindgen]\nimpl MyClass {\n\n    #[node_bindgen(constructor)]\n    fn new(val: f64) -\u003e Self {\n        Self { val }\n    }\n\n    #[node_bindgen]\n    fn plus_one(\u0026self) -\u003e f64 {\n        self.val + 1.0\n    }\n\n    #[node_bindgen(getter)]\n    fn value(\u0026self) -\u003e f64 {\n        self.val\n    }\n}\n```\n\n```js\nlet addon = require('./dist');\nconst assert = require('assert');\n\nlet obj = new addon.MyObject(10);\nassert.equal(obj.value,10,\"verify value works\");\nassert.equal(obj.plusOne(),11);\n```\n\nThere are more features in the examples folder.\n\n## Windows + Electron Support\nWhen using node-bindgen with electron on Windows, `nj-build` must\ncompile a C++ file, `win_delay_load_hook.cc`, and therefore it is required that the development\nenvironment has a valid C/C++ compiler.\n\n\u003e If your machine does not have a valid C/C++ compiler, install [Microsoft VSCode](https://code.visualstudio.com/docs/cpp/config-mingw).\n\nIn the future, this file will be re-written in Rust, removing this dependency.\n\nJust make sure that you are compiling the rust module using\n```sh\nnpx electron-build-env nj-cli build --release\n```\n\notherwise you will get dreaded  `A dynamic link library (DLL) initialization routine failed` when importing the rust module in electron\n\n## Preparing npm packages\n\nNode module generated with `node-bindgen` can be used directly in any node JS project, just copied `index.node` into it. But in case of direct access to a module IDE will not highlight available functions, classes etc. Usually, this is not comfortable and makes the risks of potential bugs higher as soon as the public API of the node module is changed.\n\nTo create a full-fledged npm package with TypeScript types definitions and all necessary JavaScript wrappers can be used a crate [tslink](https://crates.io/crates/tslink).\n\n`tslink` crate generates files `*.d.ts`, `*.js` and `package.json` with a description of the npm module. Such package could be integrated into an end-project with minimal effort. \n\nIn addition, because `tslink` generates TypeScript types definitions, any changes on the native node module (`index.node`) will be highlighted by `TypeScript` compiler and it makes the risk of bugs (related to changed API or public data types) much lower.\n\nFor example,\n\n```rust,ignore\n#[macro_use] extern crate tslink;\nuse tslink::tslink;\nuse node_bindgen::derive::node_bindgen;\n\nstruct MyScruct {\n    inc: i32,\n}\n\n#[tslink(class)]\n#[node_bindgen]\nimpl MyScruct {\n    #[tslink(constructor)]\n    #[node_bindgen(constructor)]\n    pub fn new(inc: i32) -\u003e Self {\n        Self { inc }\n    }\n\n    #[tslink(snake_case_naming)]\n    #[node_bindgen]\n    fn inc_my_number(\u0026self, a: i32) -\u003e i32 {\n        a + self.inc\n    }\n}\n```\n\nWould be represented (`*.d.ts`) as\n\n```ts\nexport declare class MyStruct {\n    constructor(inc: number);\n    incMyNumber(a: number): number;\n}\n```\n\nPay your attention, call of `#[tslink]` should be always above of call `#[node_bindgen]`.\n\nAlso, please **note**, `node-bindgen` by default applies snake case naming to methods. You should use `#[tslink(snake_case_naming)]` to consider this moment (see more on [crate page](https://docs.rs/tslink/0.1.0/tslink)).\n\n`tslink` requires a configuration in `Cargo.toml` (section `[tslink]`) of the root of your project. A configuration should include a valid path to the native node module. By default `node-bindgen` creates `index.node` in `./dist` folder of your `root`.\n\nFile: `./Cargo.toml` (in a `root` of project):\n\n```toml\n[project]\n# ...\n[lib]\n# ...\n[tslink]\nnode = \"./dist/index.node\"\n```\n\nFull example of usage `tslink` and `node-bindgen` is [here](https://github.com/icsmw/tslink/tree/master/examples/node_bindgen).\n\nSee more API documentation on a `tslink` [crate page](https://docs.rs/tslink/0.1.0/tslink).\n\n**Note**. The node-bindgen's developers are not responsible for the correctness of the work tslink crate. All possible issues and feature requests related to tslink should be addressed to tslink's developers.\n\n## Contributing\n\nIf you'd like to contribute to the project, please read our [Contributing guide](CONTRIBUTING.md).\n\n## License\n\nThis project is licensed under the [Apache license](LICENSE-APACHE).\n","funding_links":[],"categories":["Rust","Development tools","开发工具 Development tools"],"sub_categories":["FFI","FFI FFI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinyon%2Fnode-bindgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finfinyon%2Fnode-bindgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finfinyon%2Fnode-bindgen/lists"}