| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
The node-api module provides Node-API bindings for writing idiomatic Zig addons for V8-based runtimes like Node.JS or Bun. Thanks to its conventions-based approach it bridges the gap seamlessly, with almost no Node-API specific code!
Install the node_api (note the underscore) dependency
> zig fetch --save https://github.com/typesafe/node-api-zig/archive/refs/tags/v0.0.4-beta.tar.gzAdd the node-api module to your library:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const mod = b.addModule("root", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
const node_api = b.dependency("node_api", .{});
mod.addImport("node-api", node_api.module("node-api"));
const lib = b.addLibrary(.{
// if Linux
.use_llvm = true,
.name = "my-native-node-module",
.root_module = mod,
});
b.installArtifact(lib);
}Initialize your Node-API extension:
const node_api = @import("node-api");
comptime {
// export encrypt function (or types, or values or pointers)
node_api.@"export"(.{
.encrypt = encrypt,
// ...
});
}
fn encrypt(
// serialized from JS string, borrowed memory
value: []const u8,
// serialized from JS object by value (use *Options for wrapped native instances)
options: Options,
// "injected" by convention, any memory allocated with it is freed after returning to JS
allocator: std.mem.Allocator,
) ![]const u8 {
const res = allocator.alloc(u8, 123);
// ...
return res; // freed by node-api
}Use your library as node module:
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const { encrypt } = require("my-native-node-module.node");
const m = encrypt("secret", { salt: "..." });There are 2 options to initialize a module:
comptime {
node_api.register(init);
}
fn init(node: node_api.NodeContext) !?node_api.NodeValue {
// init & return `exports` value/object/function
}The node_api.init initialization function as well as any
Struct types, functions, fields, parameters and return values are all converted by convention. Unsupported types result in compile errors.
| Native type | Node type | Remarks |
|---|---|---|
| type | Class or Function | Returning or passing a struct type to JS, turns it into a class. Returning or passing a fn, turns it into a JS-callable, well, function. |
| i32,i64,u32 | number | |
| u64 | BigInt | |
| []const u8, []u8 | string | UTF-8 |
| []const T, []T | array | |
| *T | Object | Passing struct pointers to JS will wrap & track them. |
| NodeValue | any | NodeValue can be used to access JS values by reference. |
Function parameters and return types can be
Native values and NodeValue instance can be converted using Convert:
Arguments can be of type:
node.defineClass transforms a Zig struct to a JS-accessible class by convention:
comptime {
node_api.register(init);
}
fn init(node: node_api.NodeContext) !?node_api.NodeValue {
// epo
return try node.serialize(.{
.MyClass = try node.defineClass(MyClass),
});
}
const MyClass = struct {
Self = @This();
field1: i32,
field2: ?[]u8,
pub fn init() Self {
return .{ .field1 = 0, .field2 = null };
}
pub fn method1(self: Self, v: i32) !void {
}
}
init maps to new.
/*
Scenarios:
native (wrapped) instance lifecycle:
external instance memory:
parameters and return values:
setting field values
frees previous value, if any
*/
| Back | FazBrowse Home | New Git URL |