11cb0ef41Sopenharmony_ci# C++ addons 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci<!--introduced_in=v0.10.0--> 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci<!-- type=misc --> 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci_Addons_ are dynamically-linked shared objects written in C++. The 81cb0ef41Sopenharmony_ci[`require()`][require] function can load addons as ordinary Node.js modules. 91cb0ef41Sopenharmony_ciAddons provide an interface between JavaScript and C/C++ libraries. 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ciThere are three options for implementing addons: Node-API, nan, or direct 121cb0ef41Sopenharmony_ciuse of internal V8, libuv, and Node.js libraries. Unless there is a need for 131cb0ef41Sopenharmony_cidirect access to functionality which is not exposed by Node-API, use Node-API. 141cb0ef41Sopenharmony_ciRefer to [C/C++ addons with Node-API](n-api.md) for more information on 151cb0ef41Sopenharmony_ciNode-API. 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciWhen not using Node-API, implementing addons is complicated, 181cb0ef41Sopenharmony_ciinvolving knowledge of several components and APIs: 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci* [V8][]: the C++ library Node.js uses to provide the 211cb0ef41Sopenharmony_ci JavaScript implementation. V8 provides the mechanisms for creating objects, 221cb0ef41Sopenharmony_ci calling functions, etc. V8's API is documented mostly in the 231cb0ef41Sopenharmony_ci `v8.h` header file (`deps/v8/include/v8.h` in the Node.js source 241cb0ef41Sopenharmony_ci tree), which is also available [online][v8-docs]. 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci* [libuv][]: The C library that implements the Node.js event loop, its worker 271cb0ef41Sopenharmony_ci threads and all of the asynchronous behaviors of the platform. It also 281cb0ef41Sopenharmony_ci serves as a cross-platform abstraction library, giving easy, POSIX-like 291cb0ef41Sopenharmony_ci access across all major operating systems to many common system tasks, such 301cb0ef41Sopenharmony_ci as interacting with the file system, sockets, timers, and system events. libuv 311cb0ef41Sopenharmony_ci also provides a threading abstraction similar to POSIX threads for 321cb0ef41Sopenharmony_ci more sophisticated asynchronous addons that need to move beyond the 331cb0ef41Sopenharmony_ci standard event loop. Addon authors should 341cb0ef41Sopenharmony_ci avoid blocking the event loop with I/O or other time-intensive tasks by 351cb0ef41Sopenharmony_ci offloading work via libuv to non-blocking system operations, worker threads, 361cb0ef41Sopenharmony_ci or a custom use of libuv threads. 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci* Internal Node.js libraries. Node.js itself exports C++ APIs that addons can 391cb0ef41Sopenharmony_ci use, the most important of which is the `node::ObjectWrap` class. 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci* Node.js includes other statically linked libraries including OpenSSL. These 421cb0ef41Sopenharmony_ci other libraries are located in the `deps/` directory in the Node.js source 431cb0ef41Sopenharmony_ci tree. Only the libuv, OpenSSL, V8, and zlib symbols are purposefully 441cb0ef41Sopenharmony_ci re-exported by Node.js and may be used to various extents by addons. See 451cb0ef41Sopenharmony_ci [Linking to libraries included with Node.js][] for additional information. 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciAll of the following examples are available for [download][] and may 481cb0ef41Sopenharmony_cibe used as the starting-point for an addon. 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci## Hello world 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciThis "Hello world" example is a simple addon, written in C++, that is the 531cb0ef41Sopenharmony_ciequivalent of the following JavaScript code: 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci```js 561cb0ef41Sopenharmony_cimodule.exports.hello = () => 'world'; 571cb0ef41Sopenharmony_ci``` 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciFirst, create the file `hello.cc`: 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci```cpp 621cb0ef41Sopenharmony_ci// hello.cc 631cb0ef41Sopenharmony_ci#include <node.h> 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_cinamespace demo { 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 681cb0ef41Sopenharmony_ciusing v8::Isolate; 691cb0ef41Sopenharmony_ciusing v8::Local; 701cb0ef41Sopenharmony_ciusing v8::Object; 711cb0ef41Sopenharmony_ciusing v8::String; 721cb0ef41Sopenharmony_ciusing v8::Value; 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_civoid Method(const FunctionCallbackInfo<Value>& args) { 751cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 761cb0ef41Sopenharmony_ci args.GetReturnValue().Set(String::NewFromUtf8( 771cb0ef41Sopenharmony_ci isolate, "world").ToLocalChecked()); 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_civoid Initialize(Local<Object> exports) { 811cb0ef41Sopenharmony_ci NODE_SET_METHOD(exports, "hello", Method); 821cb0ef41Sopenharmony_ci} 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci} // namespace demo 871cb0ef41Sopenharmony_ci``` 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ciAll Node.js addons must export an initialization function following 901cb0ef41Sopenharmony_cithe pattern: 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci```cpp 931cb0ef41Sopenharmony_civoid Initialize(Local<Object> exports); 941cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) 951cb0ef41Sopenharmony_ci``` 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ciThere is no semi-colon after `NODE_MODULE` as it's not a function (see 981cb0ef41Sopenharmony_ci`node.h`). 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ciThe `module_name` must match the filename of the final binary (excluding 1011cb0ef41Sopenharmony_cithe `.node` suffix). 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ciIn the `hello.cc` example, then, the initialization function is `Initialize` 1041cb0ef41Sopenharmony_ciand the addon module name is `addon`. 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ciWhen building addons with `node-gyp`, using the macro `NODE_GYP_MODULE_NAME` as 1071cb0ef41Sopenharmony_cithe first parameter of `NODE_MODULE()` will ensure that the name of the final 1081cb0ef41Sopenharmony_cibinary will be passed to `NODE_MODULE()`. 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ciAddons defined with `NODE_MODULE()` can not be loaded in multiple contexts or 1111cb0ef41Sopenharmony_cimultiple threads at the same time. 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ci### Context-aware addons 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ciThere are environments in which Node.js addons may need to be loaded multiple 1161cb0ef41Sopenharmony_citimes in multiple contexts. For example, the [Electron][] runtime runs multiple 1171cb0ef41Sopenharmony_ciinstances of Node.js in a single process. Each instance will have its own 1181cb0ef41Sopenharmony_ci`require()` cache, and thus each instance will need a native addon to behave 1191cb0ef41Sopenharmony_cicorrectly when loaded via `require()`. This means that the addon 1201cb0ef41Sopenharmony_cimust support multiple initializations. 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ciA context-aware addon can be constructed by using the macro 1231cb0ef41Sopenharmony_ci`NODE_MODULE_INITIALIZER`, which expands to the name of a function which Node.js 1241cb0ef41Sopenharmony_ciwill expect to find when it loads an addon. An addon can thus be initialized as 1251cb0ef41Sopenharmony_ciin the following example: 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci```cpp 1281cb0ef41Sopenharmony_ciusing namespace v8; 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ciextern "C" NODE_MODULE_EXPORT void 1311cb0ef41Sopenharmony_ciNODE_MODULE_INITIALIZER(Local<Object> exports, 1321cb0ef41Sopenharmony_ci Local<Value> module, 1331cb0ef41Sopenharmony_ci Local<Context> context) { 1341cb0ef41Sopenharmony_ci /* Perform addon initialization steps here. */ 1351cb0ef41Sopenharmony_ci} 1361cb0ef41Sopenharmony_ci``` 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ciAnother option is to use the macro `NODE_MODULE_INIT()`, which will also 1391cb0ef41Sopenharmony_ciconstruct a context-aware addon. Unlike `NODE_MODULE()`, which is used to 1401cb0ef41Sopenharmony_ciconstruct an addon around a given addon initializer function, 1411cb0ef41Sopenharmony_ci`NODE_MODULE_INIT()` serves as the declaration of such an initializer to be 1421cb0ef41Sopenharmony_cifollowed by a function body. 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ciThe following three variables may be used inside the function body following an 1451cb0ef41Sopenharmony_ciinvocation of `NODE_MODULE_INIT()`: 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci* `Local<Object> exports`, 1481cb0ef41Sopenharmony_ci* `Local<Value> module`, and 1491cb0ef41Sopenharmony_ci* `Local<Context> context` 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ciThe choice to build a context-aware addon carries with it the responsibility of 1521cb0ef41Sopenharmony_cicarefully managing global static data. Since the addon may be loaded multiple 1531cb0ef41Sopenharmony_citimes, potentially even from different threads, any global static data stored 1541cb0ef41Sopenharmony_ciin the addon must be properly protected, and must not contain any persistent 1551cb0ef41Sopenharmony_cireferences to JavaScript objects. The reason for this is that JavaScript 1561cb0ef41Sopenharmony_ciobjects are only valid in one context, and will likely cause a crash when 1571cb0ef41Sopenharmony_ciaccessed from the wrong context or from a different thread than the one on which 1581cb0ef41Sopenharmony_cithey were created. 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ciThe context-aware addon can be structured to avoid global static data by 1611cb0ef41Sopenharmony_ciperforming the following steps: 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci* Define a class which will hold per-addon-instance data and which has a static 1641cb0ef41Sopenharmony_ci member of the form 1651cb0ef41Sopenharmony_ci ```cpp 1661cb0ef41Sopenharmony_ci static void DeleteInstance(void* data) { 1671cb0ef41Sopenharmony_ci // Cast `data` to an instance of the class and delete it. 1681cb0ef41Sopenharmony_ci } 1691cb0ef41Sopenharmony_ci ``` 1701cb0ef41Sopenharmony_ci* Heap-allocate an instance of this class in the addon initializer. This can be 1711cb0ef41Sopenharmony_ci accomplished using the `new` keyword. 1721cb0ef41Sopenharmony_ci* Call `node::AddEnvironmentCleanupHook()`, passing it the above-created 1731cb0ef41Sopenharmony_ci instance and a pointer to `DeleteInstance()`. This will ensure the instance is 1741cb0ef41Sopenharmony_ci deleted when the environment is torn down. 1751cb0ef41Sopenharmony_ci* Store the instance of the class in a `v8::External`, and 1761cb0ef41Sopenharmony_ci* Pass the `v8::External` to all methods exposed to JavaScript by passing it 1771cb0ef41Sopenharmony_ci to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the 1781cb0ef41Sopenharmony_ci native-backed JavaScript functions. The third parameter of 1791cb0ef41Sopenharmony_ci `v8::FunctionTemplate::New()` or `v8::Function::New()` accepts the 1801cb0ef41Sopenharmony_ci `v8::External` and makes it available in the native callback using the 1811cb0ef41Sopenharmony_ci `v8::FunctionCallbackInfo::Data()` method. 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ciThis will ensure that the per-addon-instance data reaches each binding that can 1841cb0ef41Sopenharmony_cibe called from JavaScript. The per-addon-instance data must also be passed into 1851cb0ef41Sopenharmony_ciany asynchronous callbacks the addon may create. 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ciThe following example illustrates the implementation of a context-aware addon: 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci```cpp 1901cb0ef41Sopenharmony_ci#include <node.h> 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ciusing namespace v8; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ciclass AddonData { 1951cb0ef41Sopenharmony_ci public: 1961cb0ef41Sopenharmony_ci explicit AddonData(Isolate* isolate): 1971cb0ef41Sopenharmony_ci call_count(0) { 1981cb0ef41Sopenharmony_ci // Ensure this per-addon-instance data is deleted at environment cleanup. 1991cb0ef41Sopenharmony_ci node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this); 2001cb0ef41Sopenharmony_ci } 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci // Per-addon data. 2031cb0ef41Sopenharmony_ci int call_count; 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci static void DeleteInstance(void* data) { 2061cb0ef41Sopenharmony_ci delete static_cast<AddonData*>(data); 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci}; 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_cistatic void Method(const v8::FunctionCallbackInfo<v8::Value>& info) { 2111cb0ef41Sopenharmony_ci // Retrieve the per-addon-instance data. 2121cb0ef41Sopenharmony_ci AddonData* data = 2131cb0ef41Sopenharmony_ci reinterpret_cast<AddonData*>(info.Data().As<External>()->Value()); 2141cb0ef41Sopenharmony_ci data->call_count++; 2151cb0ef41Sopenharmony_ci info.GetReturnValue().Set((double)data->call_count); 2161cb0ef41Sopenharmony_ci} 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci// Initialize this addon to be context-aware. 2191cb0ef41Sopenharmony_ciNODE_MODULE_INIT(/* exports, module, context */) { 2201cb0ef41Sopenharmony_ci Isolate* isolate = context->GetIsolate(); 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci // Create a new instance of `AddonData` for this instance of the addon and 2231cb0ef41Sopenharmony_ci // tie its life cycle to that of the Node.js environment. 2241cb0ef41Sopenharmony_ci AddonData* data = new AddonData(isolate); 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci // Wrap the data in a `v8::External` so we can pass it to the method we 2271cb0ef41Sopenharmony_ci // expose. 2281cb0ef41Sopenharmony_ci Local<External> external = External::New(isolate, data); 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci // Expose the method `Method` to JavaScript, and make sure it receives the 2311cb0ef41Sopenharmony_ci // per-addon-instance data we created above by passing `external` as the 2321cb0ef41Sopenharmony_ci // third parameter to the `FunctionTemplate` constructor. 2331cb0ef41Sopenharmony_ci exports->Set(context, 2341cb0ef41Sopenharmony_ci String::NewFromUtf8(isolate, "method").ToLocalChecked(), 2351cb0ef41Sopenharmony_ci FunctionTemplate::New(isolate, Method, external) 2361cb0ef41Sopenharmony_ci ->GetFunction(context).ToLocalChecked()).FromJust(); 2371cb0ef41Sopenharmony_ci} 2381cb0ef41Sopenharmony_ci``` 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci#### Worker support 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ci<!-- YAML 2431cb0ef41Sopenharmony_cichanges: 2441cb0ef41Sopenharmony_ci - version: 2451cb0ef41Sopenharmony_ci - v14.8.0 2461cb0ef41Sopenharmony_ci - v12.19.0 2471cb0ef41Sopenharmony_ci pr-url: https://github.com/nodejs/node/pull/34572 2481cb0ef41Sopenharmony_ci description: Cleanup hooks may now be asynchronous. 2491cb0ef41Sopenharmony_ci--> 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ciIn order to be loaded from multiple Node.js environments, 2521cb0ef41Sopenharmony_cisuch as a main thread and a Worker thread, an add-on needs to either: 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ci* Be an Node-API addon, or 2551cb0ef41Sopenharmony_ci* Be declared as context-aware using `NODE_MODULE_INIT()` as described above 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ciIn order to support [`Worker`][] threads, addons need to clean up any resources 2581cb0ef41Sopenharmony_cithey may have allocated when such a thread exists. This can be achieved through 2591cb0ef41Sopenharmony_cithe usage of the `AddEnvironmentCleanupHook()` function: 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci```cpp 2621cb0ef41Sopenharmony_civoid AddEnvironmentCleanupHook(v8::Isolate* isolate, 2631cb0ef41Sopenharmony_ci void (*fun)(void* arg), 2641cb0ef41Sopenharmony_ci void* arg); 2651cb0ef41Sopenharmony_ci``` 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ciThis function adds a hook that will run before a given Node.js instance shuts 2681cb0ef41Sopenharmony_cidown. If necessary, such hooks can be removed before they are run using 2691cb0ef41Sopenharmony_ci`RemoveEnvironmentCleanupHook()`, which has the same signature. Callbacks are 2701cb0ef41Sopenharmony_cirun in last-in first-out order. 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ciIf necessary, there is an additional pair of `AddEnvironmentCleanupHook()` 2731cb0ef41Sopenharmony_ciand `RemoveEnvironmentCleanupHook()` overloads, where the cleanup hook takes a 2741cb0ef41Sopenharmony_cicallback function. This can be used for shutting down asynchronous resources, 2751cb0ef41Sopenharmony_cisuch as any libuv handles registered by the addon. 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ciThe following `addon.cc` uses `AddEnvironmentCleanupHook`: 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci```cpp 2801cb0ef41Sopenharmony_ci// addon.cc 2811cb0ef41Sopenharmony_ci#include <node.h> 2821cb0ef41Sopenharmony_ci#include <assert.h> 2831cb0ef41Sopenharmony_ci#include <stdlib.h> 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_ciusing node::AddEnvironmentCleanupHook; 2861cb0ef41Sopenharmony_ciusing v8::HandleScope; 2871cb0ef41Sopenharmony_ciusing v8::Isolate; 2881cb0ef41Sopenharmony_ciusing v8::Local; 2891cb0ef41Sopenharmony_ciusing v8::Object; 2901cb0ef41Sopenharmony_ci 2911cb0ef41Sopenharmony_ci// Note: In a real-world application, do not rely on static/global data. 2921cb0ef41Sopenharmony_cistatic char cookie[] = "yum yum"; 2931cb0ef41Sopenharmony_cistatic int cleanup_cb1_called = 0; 2941cb0ef41Sopenharmony_cistatic int cleanup_cb2_called = 0; 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_cistatic void cleanup_cb1(void* arg) { 2971cb0ef41Sopenharmony_ci Isolate* isolate = static_cast<Isolate*>(arg); 2981cb0ef41Sopenharmony_ci HandleScope scope(isolate); 2991cb0ef41Sopenharmony_ci Local<Object> obj = Object::New(isolate); 3001cb0ef41Sopenharmony_ci assert(!obj.IsEmpty()); // assert VM is still alive 3011cb0ef41Sopenharmony_ci assert(obj->IsObject()); 3021cb0ef41Sopenharmony_ci cleanup_cb1_called++; 3031cb0ef41Sopenharmony_ci} 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_cistatic void cleanup_cb2(void* arg) { 3061cb0ef41Sopenharmony_ci assert(arg == static_cast<void*>(cookie)); 3071cb0ef41Sopenharmony_ci cleanup_cb2_called++; 3081cb0ef41Sopenharmony_ci} 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_cistatic void sanity_check(void*) { 3111cb0ef41Sopenharmony_ci assert(cleanup_cb1_called == 1); 3121cb0ef41Sopenharmony_ci assert(cleanup_cb2_called == 1); 3131cb0ef41Sopenharmony_ci} 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci// Initialize this addon to be context-aware. 3161cb0ef41Sopenharmony_ciNODE_MODULE_INIT(/* exports, module, context */) { 3171cb0ef41Sopenharmony_ci Isolate* isolate = context->GetIsolate(); 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci AddEnvironmentCleanupHook(isolate, sanity_check, nullptr); 3201cb0ef41Sopenharmony_ci AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie); 3211cb0ef41Sopenharmony_ci AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate); 3221cb0ef41Sopenharmony_ci} 3231cb0ef41Sopenharmony_ci``` 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ciTest in JavaScript by running: 3261cb0ef41Sopenharmony_ci 3271cb0ef41Sopenharmony_ci```js 3281cb0ef41Sopenharmony_ci// test.js 3291cb0ef41Sopenharmony_cirequire('./build/Release/addon'); 3301cb0ef41Sopenharmony_ci``` 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci### Building 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ciOnce the source code has been written, it must be compiled into the binary 3351cb0ef41Sopenharmony_ci`addon.node` file. To do so, create a file called `binding.gyp` in the 3361cb0ef41Sopenharmony_citop-level of the project describing the build configuration of the module 3371cb0ef41Sopenharmony_ciusing a JSON-like format. This file is used by [node-gyp][], a tool written 3381cb0ef41Sopenharmony_cispecifically to compile Node.js addons. 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci```json 3411cb0ef41Sopenharmony_ci{ 3421cb0ef41Sopenharmony_ci "targets": [ 3431cb0ef41Sopenharmony_ci { 3441cb0ef41Sopenharmony_ci "target_name": "addon", 3451cb0ef41Sopenharmony_ci "sources": [ "hello.cc" ] 3461cb0ef41Sopenharmony_ci } 3471cb0ef41Sopenharmony_ci ] 3481cb0ef41Sopenharmony_ci} 3491cb0ef41Sopenharmony_ci``` 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ciA version of the `node-gyp` utility is bundled and distributed with 3521cb0ef41Sopenharmony_ciNode.js as part of `npm`. This version is not made directly available for 3531cb0ef41Sopenharmony_cidevelopers to use and is intended only to support the ability to use the 3541cb0ef41Sopenharmony_ci`npm install` command to compile and install addons. Developers who wish to 3551cb0ef41Sopenharmony_ciuse `node-gyp` directly can install it using the command 3561cb0ef41Sopenharmony_ci`npm install -g node-gyp`. See the `node-gyp` [installation instructions][] for 3571cb0ef41Sopenharmony_cimore information, including platform-specific requirements. 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ciOnce the `binding.gyp` file has been created, use `node-gyp configure` to 3601cb0ef41Sopenharmony_cigenerate the appropriate project build files for the current platform. This 3611cb0ef41Sopenharmony_ciwill generate either a `Makefile` (on Unix platforms) or a `vcxproj` file 3621cb0ef41Sopenharmony_ci(on Windows) in the `build/` directory. 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ciNext, invoke the `node-gyp build` command to generate the compiled `addon.node` 3651cb0ef41Sopenharmony_cifile. This will be put into the `build/Release/` directory. 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ciWhen using `npm install` to install a Node.js addon, npm uses its own bundled 3681cb0ef41Sopenharmony_civersion of `node-gyp` to perform this same set of actions, generating a 3691cb0ef41Sopenharmony_cicompiled version of the addon for the user's platform on demand. 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ciOnce built, the binary addon can be used from within Node.js by pointing 3721cb0ef41Sopenharmony_ci[`require()`][require] to the built `addon.node` module: 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci```js 3751cb0ef41Sopenharmony_ci// hello.js 3761cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ciconsole.log(addon.hello()); 3791cb0ef41Sopenharmony_ci// Prints: 'world' 3801cb0ef41Sopenharmony_ci``` 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ciBecause the exact path to the compiled addon binary can vary depending on how 3831cb0ef41Sopenharmony_ciit is compiled (i.e. sometimes it may be in `./build/Debug/`), addons can use 3841cb0ef41Sopenharmony_cithe [bindings][] package to load the compiled module. 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ciWhile the `bindings` package implementation is more sophisticated in how it 3871cb0ef41Sopenharmony_cilocates addon modules, it is essentially using a `try…catch` pattern similar to: 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_ci```js 3901cb0ef41Sopenharmony_citry { 3911cb0ef41Sopenharmony_ci return require('./build/Release/addon.node'); 3921cb0ef41Sopenharmony_ci} catch (err) { 3931cb0ef41Sopenharmony_ci return require('./build/Debug/addon.node'); 3941cb0ef41Sopenharmony_ci} 3951cb0ef41Sopenharmony_ci``` 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci### Linking to libraries included with Node.js 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ciNode.js uses statically linked libraries such as V8, libuv, and OpenSSL. All 4001cb0ef41Sopenharmony_ciaddons are required to link to V8 and may link to any of the other dependencies 4011cb0ef41Sopenharmony_cias well. Typically, this is as simple as including the appropriate 4021cb0ef41Sopenharmony_ci`#include <...>` statements (e.g. `#include <v8.h>`) and `node-gyp` will locate 4031cb0ef41Sopenharmony_cithe appropriate headers automatically. However, there are a few caveats to be 4041cb0ef41Sopenharmony_ciaware of: 4051cb0ef41Sopenharmony_ci 4061cb0ef41Sopenharmony_ci* When `node-gyp` runs, it will detect the specific release version of Node.js 4071cb0ef41Sopenharmony_ci and download either the full source tarball or just the headers. If the full 4081cb0ef41Sopenharmony_ci source is downloaded, addons will have complete access to the full set of 4091cb0ef41Sopenharmony_ci Node.js dependencies. However, if only the Node.js headers are downloaded, 4101cb0ef41Sopenharmony_ci then only the symbols exported by Node.js will be available. 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci* `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js 4131cb0ef41Sopenharmony_ci source image. Using this option, the addon will have access to the full set of 4141cb0ef41Sopenharmony_ci dependencies. 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci### Loading addons using `require()` 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ciThe filename extension of the compiled addon binary is `.node` (as opposed 4191cb0ef41Sopenharmony_cito `.dll` or `.so`). The [`require()`][require] function is written to look for 4201cb0ef41Sopenharmony_cifiles with the `.node` file extension and initialize those as dynamically-linked 4211cb0ef41Sopenharmony_cilibraries. 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ciWhen calling [`require()`][require], the `.node` extension can usually be 4241cb0ef41Sopenharmony_ciomitted and Node.js will still find and initialize the addon. One caveat, 4251cb0ef41Sopenharmony_cihowever, is that Node.js will first attempt to locate and load modules or 4261cb0ef41Sopenharmony_ciJavaScript files that happen to share the same base name. For instance, if 4271cb0ef41Sopenharmony_cithere is a file `addon.js` in the same directory as the binary `addon.node`, 4281cb0ef41Sopenharmony_cithen [`require('addon')`][require] will give precedence to the `addon.js` file 4291cb0ef41Sopenharmony_ciand load it instead. 4301cb0ef41Sopenharmony_ci 4311cb0ef41Sopenharmony_ci## Native abstractions for Node.js 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ciEach of the examples illustrated in this document directly use the 4341cb0ef41Sopenharmony_ciNode.js and V8 APIs for implementing addons. The V8 API can, and has, changed 4351cb0ef41Sopenharmony_cidramatically from one V8 release to the next (and one major Node.js release to 4361cb0ef41Sopenharmony_cithe next). With each change, addons may need to be updated and recompiled in 4371cb0ef41Sopenharmony_ciorder to continue functioning. The Node.js release schedule is designed to 4381cb0ef41Sopenharmony_ciminimize the frequency and impact of such changes but there is little that 4391cb0ef41Sopenharmony_ciNode.js can do to ensure stability of the V8 APIs. 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ciThe [Native Abstractions for Node.js][] (or `nan`) provide a set of tools that 4421cb0ef41Sopenharmony_ciaddon developers are recommended to use to keep compatibility between past and 4431cb0ef41Sopenharmony_cifuture releases of V8 and Node.js. See the `nan` [examples][] for an 4441cb0ef41Sopenharmony_ciillustration of how it can be used. 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci## Node-API 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci> Stability: 2 - Stable 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ciNode-API is an API for building native addons. It is independent from 4511cb0ef41Sopenharmony_cithe underlying JavaScript runtime (e.g. V8) and is maintained as part of 4521cb0ef41Sopenharmony_ciNode.js itself. This API will be Application Binary Interface (ABI) stable 4531cb0ef41Sopenharmony_ciacross versions of Node.js. It is intended to insulate addons from 4541cb0ef41Sopenharmony_cichanges in the underlying JavaScript engine and allow modules 4551cb0ef41Sopenharmony_cicompiled for one version to run on later versions of Node.js without 4561cb0ef41Sopenharmony_cirecompilation. Addons are built/packaged with the same approach/tools 4571cb0ef41Sopenharmony_cioutlined in this document (node-gyp, etc.). The only difference is the 4581cb0ef41Sopenharmony_ciset of APIs that are used by the native code. Instead of using the V8 4591cb0ef41Sopenharmony_cior [Native Abstractions for Node.js][] APIs, the functions available 4601cb0ef41Sopenharmony_ciin the Node-API are used. 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ciCreating and maintaining an addon that benefits from the ABI stability 4631cb0ef41Sopenharmony_ciprovided by Node-API carries with it certain 4641cb0ef41Sopenharmony_ci[implementation considerations][]. 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ciTo use Node-API in the above "Hello world" example, replace the content of 4671cb0ef41Sopenharmony_ci`hello.cc` with the following. All other instructions remain the same. 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ci```cpp 4701cb0ef41Sopenharmony_ci// hello.cc using Node-API 4711cb0ef41Sopenharmony_ci#include <node_api.h> 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_cinamespace demo { 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_cinapi_value Method(napi_env env, napi_callback_info args) { 4761cb0ef41Sopenharmony_ci napi_value greeting; 4771cb0ef41Sopenharmony_ci napi_status status; 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting); 4801cb0ef41Sopenharmony_ci if (status != napi_ok) return nullptr; 4811cb0ef41Sopenharmony_ci return greeting; 4821cb0ef41Sopenharmony_ci} 4831cb0ef41Sopenharmony_ci 4841cb0ef41Sopenharmony_cinapi_value init(napi_env env, napi_value exports) { 4851cb0ef41Sopenharmony_ci napi_status status; 4861cb0ef41Sopenharmony_ci napi_value fn; 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn); 4891cb0ef41Sopenharmony_ci if (status != napi_ok) return nullptr; 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_ci status = napi_set_named_property(env, exports, "hello", fn); 4921cb0ef41Sopenharmony_ci if (status != napi_ok) return nullptr; 4931cb0ef41Sopenharmony_ci return exports; 4941cb0ef41Sopenharmony_ci} 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ciNAPI_MODULE(NODE_GYP_MODULE_NAME, init) 4971cb0ef41Sopenharmony_ci 4981cb0ef41Sopenharmony_ci} // namespace demo 4991cb0ef41Sopenharmony_ci``` 5001cb0ef41Sopenharmony_ci 5011cb0ef41Sopenharmony_ciThe functions available and how to use them are documented in 5021cb0ef41Sopenharmony_ci[C/C++ addons with Node-API](n-api.md). 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci## Addon examples 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ciFollowing are some example addons intended to help developers get started. The 5071cb0ef41Sopenharmony_ciexamples use the V8 APIs. Refer to the online [V8 reference][v8-docs] 5081cb0ef41Sopenharmony_cifor help with the various V8 calls, and V8's [Embedder's Guide][] for an 5091cb0ef41Sopenharmony_ciexplanation of several concepts used such as handles, scopes, function 5101cb0ef41Sopenharmony_citemplates, etc. 5111cb0ef41Sopenharmony_ci 5121cb0ef41Sopenharmony_ciEach of these examples using the following `binding.gyp` file: 5131cb0ef41Sopenharmony_ci 5141cb0ef41Sopenharmony_ci```json 5151cb0ef41Sopenharmony_ci{ 5161cb0ef41Sopenharmony_ci "targets": [ 5171cb0ef41Sopenharmony_ci { 5181cb0ef41Sopenharmony_ci "target_name": "addon", 5191cb0ef41Sopenharmony_ci "sources": [ "addon.cc" ] 5201cb0ef41Sopenharmony_ci } 5211cb0ef41Sopenharmony_ci ] 5221cb0ef41Sopenharmony_ci} 5231cb0ef41Sopenharmony_ci``` 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ciIn cases where there is more than one `.cc` file, simply add the additional 5261cb0ef41Sopenharmony_cifilename to the `sources` array: 5271cb0ef41Sopenharmony_ci 5281cb0ef41Sopenharmony_ci```json 5291cb0ef41Sopenharmony_ci"sources": ["addon.cc", "myexample.cc"] 5301cb0ef41Sopenharmony_ci``` 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ciOnce the `binding.gyp` file is ready, the example addons can be configured and 5331cb0ef41Sopenharmony_cibuilt using `node-gyp`: 5341cb0ef41Sopenharmony_ci 5351cb0ef41Sopenharmony_ci```console 5361cb0ef41Sopenharmony_ci$ node-gyp configure build 5371cb0ef41Sopenharmony_ci``` 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ci### Function arguments 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ciAddons will typically expose objects and functions that can be accessed from 5421cb0ef41Sopenharmony_ciJavaScript running within Node.js. When functions are invoked from JavaScript, 5431cb0ef41Sopenharmony_cithe input arguments and return value must be mapped to and from the C/C++ 5441cb0ef41Sopenharmony_cicode. 5451cb0ef41Sopenharmony_ci 5461cb0ef41Sopenharmony_ciThe following example illustrates how to read function arguments passed from 5471cb0ef41Sopenharmony_ciJavaScript and how to return a result: 5481cb0ef41Sopenharmony_ci 5491cb0ef41Sopenharmony_ci```cpp 5501cb0ef41Sopenharmony_ci// addon.cc 5511cb0ef41Sopenharmony_ci#include <node.h> 5521cb0ef41Sopenharmony_ci 5531cb0ef41Sopenharmony_cinamespace demo { 5541cb0ef41Sopenharmony_ci 5551cb0ef41Sopenharmony_ciusing v8::Exception; 5561cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 5571cb0ef41Sopenharmony_ciusing v8::Isolate; 5581cb0ef41Sopenharmony_ciusing v8::Local; 5591cb0ef41Sopenharmony_ciusing v8::Number; 5601cb0ef41Sopenharmony_ciusing v8::Object; 5611cb0ef41Sopenharmony_ciusing v8::String; 5621cb0ef41Sopenharmony_ciusing v8::Value; 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci// This is the implementation of the "add" method 5651cb0ef41Sopenharmony_ci// Input arguments are passed using the 5661cb0ef41Sopenharmony_ci// const FunctionCallbackInfo<Value>& args struct 5671cb0ef41Sopenharmony_civoid Add(const FunctionCallbackInfo<Value>& args) { 5681cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci // Check the number of arguments passed. 5711cb0ef41Sopenharmony_ci if (args.Length() < 2) { 5721cb0ef41Sopenharmony_ci // Throw an Error that is passed back to JavaScript 5731cb0ef41Sopenharmony_ci isolate->ThrowException(Exception::TypeError( 5741cb0ef41Sopenharmony_ci String::NewFromUtf8(isolate, 5751cb0ef41Sopenharmony_ci "Wrong number of arguments").ToLocalChecked())); 5761cb0ef41Sopenharmony_ci return; 5771cb0ef41Sopenharmony_ci } 5781cb0ef41Sopenharmony_ci 5791cb0ef41Sopenharmony_ci // Check the argument types 5801cb0ef41Sopenharmony_ci if (!args[0]->IsNumber() || !args[1]->IsNumber()) { 5811cb0ef41Sopenharmony_ci isolate->ThrowException(Exception::TypeError( 5821cb0ef41Sopenharmony_ci String::NewFromUtf8(isolate, 5831cb0ef41Sopenharmony_ci "Wrong arguments").ToLocalChecked())); 5841cb0ef41Sopenharmony_ci return; 5851cb0ef41Sopenharmony_ci } 5861cb0ef41Sopenharmony_ci 5871cb0ef41Sopenharmony_ci // Perform the operation 5881cb0ef41Sopenharmony_ci double value = 5891cb0ef41Sopenharmony_ci args[0].As<Number>()->Value() + args[1].As<Number>()->Value(); 5901cb0ef41Sopenharmony_ci Local<Number> num = Number::New(isolate, value); 5911cb0ef41Sopenharmony_ci 5921cb0ef41Sopenharmony_ci // Set the return value (using the passed in 5931cb0ef41Sopenharmony_ci // FunctionCallbackInfo<Value>&) 5941cb0ef41Sopenharmony_ci args.GetReturnValue().Set(num); 5951cb0ef41Sopenharmony_ci} 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_civoid Init(Local<Object> exports) { 5981cb0ef41Sopenharmony_ci NODE_SET_METHOD(exports, "add", Add); 5991cb0ef41Sopenharmony_ci} 6001cb0ef41Sopenharmony_ci 6011cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Init) 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci} // namespace demo 6041cb0ef41Sopenharmony_ci``` 6051cb0ef41Sopenharmony_ci 6061cb0ef41Sopenharmony_ciOnce compiled, the example addon can be required and used from within Node.js: 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ci```js 6091cb0ef41Sopenharmony_ci// test.js 6101cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 6111cb0ef41Sopenharmony_ci 6121cb0ef41Sopenharmony_ciconsole.log('This should be eight:', addon.add(3, 5)); 6131cb0ef41Sopenharmony_ci``` 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci### Callbacks 6161cb0ef41Sopenharmony_ci 6171cb0ef41Sopenharmony_ciIt is common practice within addons to pass JavaScript functions to a C++ 6181cb0ef41Sopenharmony_cifunction and execute them from there. The following example illustrates how 6191cb0ef41Sopenharmony_cito invoke such callbacks: 6201cb0ef41Sopenharmony_ci 6211cb0ef41Sopenharmony_ci```cpp 6221cb0ef41Sopenharmony_ci// addon.cc 6231cb0ef41Sopenharmony_ci#include <node.h> 6241cb0ef41Sopenharmony_ci 6251cb0ef41Sopenharmony_cinamespace demo { 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ciusing v8::Context; 6281cb0ef41Sopenharmony_ciusing v8::Function; 6291cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 6301cb0ef41Sopenharmony_ciusing v8::Isolate; 6311cb0ef41Sopenharmony_ciusing v8::Local; 6321cb0ef41Sopenharmony_ciusing v8::Null; 6331cb0ef41Sopenharmony_ciusing v8::Object; 6341cb0ef41Sopenharmony_ciusing v8::String; 6351cb0ef41Sopenharmony_ciusing v8::Value; 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_civoid RunCallback(const FunctionCallbackInfo<Value>& args) { 6381cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 6391cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 6401cb0ef41Sopenharmony_ci Local<Function> cb = Local<Function>::Cast(args[0]); 6411cb0ef41Sopenharmony_ci const unsigned argc = 1; 6421cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { 6431cb0ef41Sopenharmony_ci String::NewFromUtf8(isolate, 6441cb0ef41Sopenharmony_ci "hello world").ToLocalChecked() }; 6451cb0ef41Sopenharmony_ci cb->Call(context, Null(isolate), argc, argv).ToLocalChecked(); 6461cb0ef41Sopenharmony_ci} 6471cb0ef41Sopenharmony_ci 6481cb0ef41Sopenharmony_civoid Init(Local<Object> exports, Local<Object> module) { 6491cb0ef41Sopenharmony_ci NODE_SET_METHOD(module, "exports", RunCallback); 6501cb0ef41Sopenharmony_ci} 6511cb0ef41Sopenharmony_ci 6521cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Init) 6531cb0ef41Sopenharmony_ci 6541cb0ef41Sopenharmony_ci} // namespace demo 6551cb0ef41Sopenharmony_ci``` 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ciThis example uses a two-argument form of `Init()` that receives the full 6581cb0ef41Sopenharmony_ci`module` object as the second argument. This allows the addon to completely 6591cb0ef41Sopenharmony_cioverwrite `exports` with a single function instead of adding the function as a 6601cb0ef41Sopenharmony_ciproperty of `exports`. 6611cb0ef41Sopenharmony_ci 6621cb0ef41Sopenharmony_ciTo test it, run the following JavaScript: 6631cb0ef41Sopenharmony_ci 6641cb0ef41Sopenharmony_ci```js 6651cb0ef41Sopenharmony_ci// test.js 6661cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 6671cb0ef41Sopenharmony_ci 6681cb0ef41Sopenharmony_ciaddon((msg) => { 6691cb0ef41Sopenharmony_ci console.log(msg); 6701cb0ef41Sopenharmony_ci// Prints: 'hello world' 6711cb0ef41Sopenharmony_ci}); 6721cb0ef41Sopenharmony_ci``` 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ciIn this example, the callback function is invoked synchronously. 6751cb0ef41Sopenharmony_ci 6761cb0ef41Sopenharmony_ci### Object factory 6771cb0ef41Sopenharmony_ci 6781cb0ef41Sopenharmony_ciAddons can create and return new objects from within a C++ function as 6791cb0ef41Sopenharmony_ciillustrated in the following example. An object is created and returned with a 6801cb0ef41Sopenharmony_ciproperty `msg` that echoes the string passed to `createObject()`: 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci```cpp 6831cb0ef41Sopenharmony_ci// addon.cc 6841cb0ef41Sopenharmony_ci#include <node.h> 6851cb0ef41Sopenharmony_ci 6861cb0ef41Sopenharmony_cinamespace demo { 6871cb0ef41Sopenharmony_ci 6881cb0ef41Sopenharmony_ciusing v8::Context; 6891cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 6901cb0ef41Sopenharmony_ciusing v8::Isolate; 6911cb0ef41Sopenharmony_ciusing v8::Local; 6921cb0ef41Sopenharmony_ciusing v8::Object; 6931cb0ef41Sopenharmony_ciusing v8::String; 6941cb0ef41Sopenharmony_ciusing v8::Value; 6951cb0ef41Sopenharmony_ci 6961cb0ef41Sopenharmony_civoid CreateObject(const FunctionCallbackInfo<Value>& args) { 6971cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 6981cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_ci Local<Object> obj = Object::New(isolate); 7011cb0ef41Sopenharmony_ci obj->Set(context, 7021cb0ef41Sopenharmony_ci String::NewFromUtf8(isolate, 7031cb0ef41Sopenharmony_ci "msg").ToLocalChecked(), 7041cb0ef41Sopenharmony_ci args[0]->ToString(context).ToLocalChecked()) 7051cb0ef41Sopenharmony_ci .FromJust(); 7061cb0ef41Sopenharmony_ci 7071cb0ef41Sopenharmony_ci args.GetReturnValue().Set(obj); 7081cb0ef41Sopenharmony_ci} 7091cb0ef41Sopenharmony_ci 7101cb0ef41Sopenharmony_civoid Init(Local<Object> exports, Local<Object> module) { 7111cb0ef41Sopenharmony_ci NODE_SET_METHOD(module, "exports", CreateObject); 7121cb0ef41Sopenharmony_ci} 7131cb0ef41Sopenharmony_ci 7141cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Init) 7151cb0ef41Sopenharmony_ci 7161cb0ef41Sopenharmony_ci} // namespace demo 7171cb0ef41Sopenharmony_ci``` 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ciTo test it in JavaScript: 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_ci```js 7221cb0ef41Sopenharmony_ci// test.js 7231cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 7241cb0ef41Sopenharmony_ci 7251cb0ef41Sopenharmony_ciconst obj1 = addon('hello'); 7261cb0ef41Sopenharmony_ciconst obj2 = addon('world'); 7271cb0ef41Sopenharmony_ciconsole.log(obj1.msg, obj2.msg); 7281cb0ef41Sopenharmony_ci// Prints: 'hello world' 7291cb0ef41Sopenharmony_ci``` 7301cb0ef41Sopenharmony_ci 7311cb0ef41Sopenharmony_ci### Function factory 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_ciAnother common scenario is creating JavaScript functions that wrap C++ 7341cb0ef41Sopenharmony_cifunctions and returning those back to JavaScript: 7351cb0ef41Sopenharmony_ci 7361cb0ef41Sopenharmony_ci```cpp 7371cb0ef41Sopenharmony_ci// addon.cc 7381cb0ef41Sopenharmony_ci#include <node.h> 7391cb0ef41Sopenharmony_ci 7401cb0ef41Sopenharmony_cinamespace demo { 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ciusing v8::Context; 7431cb0ef41Sopenharmony_ciusing v8::Function; 7441cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 7451cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 7461cb0ef41Sopenharmony_ciusing v8::Isolate; 7471cb0ef41Sopenharmony_ciusing v8::Local; 7481cb0ef41Sopenharmony_ciusing v8::Object; 7491cb0ef41Sopenharmony_ciusing v8::String; 7501cb0ef41Sopenharmony_ciusing v8::Value; 7511cb0ef41Sopenharmony_ci 7521cb0ef41Sopenharmony_civoid MyFunction(const FunctionCallbackInfo<Value>& args) { 7531cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 7541cb0ef41Sopenharmony_ci args.GetReturnValue().Set(String::NewFromUtf8( 7551cb0ef41Sopenharmony_ci isolate, "hello world").ToLocalChecked()); 7561cb0ef41Sopenharmony_ci} 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_civoid CreateFunction(const FunctionCallbackInfo<Value>& args) { 7591cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 7601cb0ef41Sopenharmony_ci 7611cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 7621cb0ef41Sopenharmony_ci Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction); 7631cb0ef41Sopenharmony_ci Local<Function> fn = tpl->GetFunction(context).ToLocalChecked(); 7641cb0ef41Sopenharmony_ci 7651cb0ef41Sopenharmony_ci // omit this to make it anonymous 7661cb0ef41Sopenharmony_ci fn->SetName(String::NewFromUtf8( 7671cb0ef41Sopenharmony_ci isolate, "theFunction").ToLocalChecked()); 7681cb0ef41Sopenharmony_ci 7691cb0ef41Sopenharmony_ci args.GetReturnValue().Set(fn); 7701cb0ef41Sopenharmony_ci} 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_civoid Init(Local<Object> exports, Local<Object> module) { 7731cb0ef41Sopenharmony_ci NODE_SET_METHOD(module, "exports", CreateFunction); 7741cb0ef41Sopenharmony_ci} 7751cb0ef41Sopenharmony_ci 7761cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, Init) 7771cb0ef41Sopenharmony_ci 7781cb0ef41Sopenharmony_ci} // namespace demo 7791cb0ef41Sopenharmony_ci``` 7801cb0ef41Sopenharmony_ci 7811cb0ef41Sopenharmony_ciTo test: 7821cb0ef41Sopenharmony_ci 7831cb0ef41Sopenharmony_ci```js 7841cb0ef41Sopenharmony_ci// test.js 7851cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 7861cb0ef41Sopenharmony_ci 7871cb0ef41Sopenharmony_ciconst fn = addon(); 7881cb0ef41Sopenharmony_ciconsole.log(fn()); 7891cb0ef41Sopenharmony_ci// Prints: 'hello world' 7901cb0ef41Sopenharmony_ci``` 7911cb0ef41Sopenharmony_ci 7921cb0ef41Sopenharmony_ci### Wrapping C++ objects 7931cb0ef41Sopenharmony_ci 7941cb0ef41Sopenharmony_ciIt is also possible to wrap C++ objects/classes in a way that allows new 7951cb0ef41Sopenharmony_ciinstances to be created using the JavaScript `new` operator: 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_ci```cpp 7981cb0ef41Sopenharmony_ci// addon.cc 7991cb0ef41Sopenharmony_ci#include <node.h> 8001cb0ef41Sopenharmony_ci#include "myobject.h" 8011cb0ef41Sopenharmony_ci 8021cb0ef41Sopenharmony_cinamespace demo { 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ciusing v8::Local; 8051cb0ef41Sopenharmony_ciusing v8::Object; 8061cb0ef41Sopenharmony_ci 8071cb0ef41Sopenharmony_civoid InitAll(Local<Object> exports) { 8081cb0ef41Sopenharmony_ci MyObject::Init(exports); 8091cb0ef41Sopenharmony_ci} 8101cb0ef41Sopenharmony_ci 8111cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, InitAll) 8121cb0ef41Sopenharmony_ci 8131cb0ef41Sopenharmony_ci} // namespace demo 8141cb0ef41Sopenharmony_ci``` 8151cb0ef41Sopenharmony_ci 8161cb0ef41Sopenharmony_ciThen, in `myobject.h`, the wrapper class inherits from `node::ObjectWrap`: 8171cb0ef41Sopenharmony_ci 8181cb0ef41Sopenharmony_ci```cpp 8191cb0ef41Sopenharmony_ci// myobject.h 8201cb0ef41Sopenharmony_ci#ifndef MYOBJECT_H 8211cb0ef41Sopenharmony_ci#define MYOBJECT_H 8221cb0ef41Sopenharmony_ci 8231cb0ef41Sopenharmony_ci#include <node.h> 8241cb0ef41Sopenharmony_ci#include <node_object_wrap.h> 8251cb0ef41Sopenharmony_ci 8261cb0ef41Sopenharmony_cinamespace demo { 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ciclass MyObject : public node::ObjectWrap { 8291cb0ef41Sopenharmony_ci public: 8301cb0ef41Sopenharmony_ci static void Init(v8::Local<v8::Object> exports); 8311cb0ef41Sopenharmony_ci 8321cb0ef41Sopenharmony_ci private: 8331cb0ef41Sopenharmony_ci explicit MyObject(double value = 0); 8341cb0ef41Sopenharmony_ci ~MyObject(); 8351cb0ef41Sopenharmony_ci 8361cb0ef41Sopenharmony_ci static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 8371cb0ef41Sopenharmony_ci static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args); 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci double value_; 8401cb0ef41Sopenharmony_ci}; 8411cb0ef41Sopenharmony_ci 8421cb0ef41Sopenharmony_ci} // namespace demo 8431cb0ef41Sopenharmony_ci 8441cb0ef41Sopenharmony_ci#endif 8451cb0ef41Sopenharmony_ci``` 8461cb0ef41Sopenharmony_ci 8471cb0ef41Sopenharmony_ciIn `myobject.cc`, implement the various methods that are to be exposed. 8481cb0ef41Sopenharmony_ciBelow, the method `plusOne()` is exposed by adding it to the constructor's 8491cb0ef41Sopenharmony_ciprototype: 8501cb0ef41Sopenharmony_ci 8511cb0ef41Sopenharmony_ci```cpp 8521cb0ef41Sopenharmony_ci// myobject.cc 8531cb0ef41Sopenharmony_ci#include "myobject.h" 8541cb0ef41Sopenharmony_ci 8551cb0ef41Sopenharmony_cinamespace demo { 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_ciusing v8::Context; 8581cb0ef41Sopenharmony_ciusing v8::Function; 8591cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 8601cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 8611cb0ef41Sopenharmony_ciusing v8::Isolate; 8621cb0ef41Sopenharmony_ciusing v8::Local; 8631cb0ef41Sopenharmony_ciusing v8::Number; 8641cb0ef41Sopenharmony_ciusing v8::Object; 8651cb0ef41Sopenharmony_ciusing v8::ObjectTemplate; 8661cb0ef41Sopenharmony_ciusing v8::String; 8671cb0ef41Sopenharmony_ciusing v8::Value; 8681cb0ef41Sopenharmony_ci 8691cb0ef41Sopenharmony_ciMyObject::MyObject(double value) : value_(value) { 8701cb0ef41Sopenharmony_ci} 8711cb0ef41Sopenharmony_ci 8721cb0ef41Sopenharmony_ciMyObject::~MyObject() { 8731cb0ef41Sopenharmony_ci} 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_civoid MyObject::Init(Local<Object> exports) { 8761cb0ef41Sopenharmony_ci Isolate* isolate = exports->GetIsolate(); 8771cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 8781cb0ef41Sopenharmony_ci 8791cb0ef41Sopenharmony_ci Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::New(isolate); 8801cb0ef41Sopenharmony_ci addon_data_tpl->SetInternalFieldCount(1); // 1 field for the MyObject::New() 8811cb0ef41Sopenharmony_ci Local<Object> addon_data = 8821cb0ef41Sopenharmony_ci addon_data_tpl->NewInstance(context).ToLocalChecked(); 8831cb0ef41Sopenharmony_ci 8841cb0ef41Sopenharmony_ci // Prepare constructor template 8851cb0ef41Sopenharmony_ci Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New, addon_data); 8861cb0ef41Sopenharmony_ci tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); 8871cb0ef41Sopenharmony_ci tpl->InstanceTemplate()->SetInternalFieldCount(1); 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci // Prototype 8901cb0ef41Sopenharmony_ci NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); 8911cb0ef41Sopenharmony_ci 8921cb0ef41Sopenharmony_ci Local<Function> constructor = tpl->GetFunction(context).ToLocalChecked(); 8931cb0ef41Sopenharmony_ci addon_data->SetInternalField(0, constructor); 8941cb0ef41Sopenharmony_ci exports->Set(context, String::NewFromUtf8( 8951cb0ef41Sopenharmony_ci isolate, "MyObject").ToLocalChecked(), 8961cb0ef41Sopenharmony_ci constructor).FromJust(); 8971cb0ef41Sopenharmony_ci} 8981cb0ef41Sopenharmony_ci 8991cb0ef41Sopenharmony_civoid MyObject::New(const FunctionCallbackInfo<Value>& args) { 9001cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 9011cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 9021cb0ef41Sopenharmony_ci 9031cb0ef41Sopenharmony_ci if (args.IsConstructCall()) { 9041cb0ef41Sopenharmony_ci // Invoked as constructor: `new MyObject(...)` 9051cb0ef41Sopenharmony_ci double value = args[0]->IsUndefined() ? 9061cb0ef41Sopenharmony_ci 0 : args[0]->NumberValue(context).FromMaybe(0); 9071cb0ef41Sopenharmony_ci MyObject* obj = new MyObject(value); 9081cb0ef41Sopenharmony_ci obj->Wrap(args.This()); 9091cb0ef41Sopenharmony_ci args.GetReturnValue().Set(args.This()); 9101cb0ef41Sopenharmony_ci } else { 9111cb0ef41Sopenharmony_ci // Invoked as plain function `MyObject(...)`, turn into construct call. 9121cb0ef41Sopenharmony_ci const int argc = 1; 9131cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { args[0] }; 9141cb0ef41Sopenharmony_ci Local<Function> cons = 9151cb0ef41Sopenharmony_ci args.Data().As<Object>()->GetInternalField(0).As<Function>(); 9161cb0ef41Sopenharmony_ci Local<Object> result = 9171cb0ef41Sopenharmony_ci cons->NewInstance(context, argc, argv).ToLocalChecked(); 9181cb0ef41Sopenharmony_ci args.GetReturnValue().Set(result); 9191cb0ef41Sopenharmony_ci } 9201cb0ef41Sopenharmony_ci} 9211cb0ef41Sopenharmony_ci 9221cb0ef41Sopenharmony_civoid MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { 9231cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 9241cb0ef41Sopenharmony_ci 9251cb0ef41Sopenharmony_ci MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder()); 9261cb0ef41Sopenharmony_ci obj->value_ += 1; 9271cb0ef41Sopenharmony_ci 9281cb0ef41Sopenharmony_ci args.GetReturnValue().Set(Number::New(isolate, obj->value_)); 9291cb0ef41Sopenharmony_ci} 9301cb0ef41Sopenharmony_ci 9311cb0ef41Sopenharmony_ci} // namespace demo 9321cb0ef41Sopenharmony_ci``` 9331cb0ef41Sopenharmony_ci 9341cb0ef41Sopenharmony_ciTo build this example, the `myobject.cc` file must be added to the 9351cb0ef41Sopenharmony_ci`binding.gyp`: 9361cb0ef41Sopenharmony_ci 9371cb0ef41Sopenharmony_ci```json 9381cb0ef41Sopenharmony_ci{ 9391cb0ef41Sopenharmony_ci "targets": [ 9401cb0ef41Sopenharmony_ci { 9411cb0ef41Sopenharmony_ci "target_name": "addon", 9421cb0ef41Sopenharmony_ci "sources": [ 9431cb0ef41Sopenharmony_ci "addon.cc", 9441cb0ef41Sopenharmony_ci "myobject.cc" 9451cb0ef41Sopenharmony_ci ] 9461cb0ef41Sopenharmony_ci } 9471cb0ef41Sopenharmony_ci ] 9481cb0ef41Sopenharmony_ci} 9491cb0ef41Sopenharmony_ci``` 9501cb0ef41Sopenharmony_ci 9511cb0ef41Sopenharmony_ciTest it with: 9521cb0ef41Sopenharmony_ci 9531cb0ef41Sopenharmony_ci```js 9541cb0ef41Sopenharmony_ci// test.js 9551cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 9561cb0ef41Sopenharmony_ci 9571cb0ef41Sopenharmony_ciconst obj = new addon.MyObject(10); 9581cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 9591cb0ef41Sopenharmony_ci// Prints: 11 9601cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 9611cb0ef41Sopenharmony_ci// Prints: 12 9621cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 9631cb0ef41Sopenharmony_ci// Prints: 13 9641cb0ef41Sopenharmony_ci``` 9651cb0ef41Sopenharmony_ci 9661cb0ef41Sopenharmony_ciThe destructor for a wrapper object will run when the object is 9671cb0ef41Sopenharmony_cigarbage-collected. For destructor testing, there are command-line flags that 9681cb0ef41Sopenharmony_cican be used to make it possible to force garbage collection. These flags are 9691cb0ef41Sopenharmony_ciprovided by the underlying V8 JavaScript engine. They are subject to change 9701cb0ef41Sopenharmony_cior removal at any time. They are not documented by Node.js or V8, and they 9711cb0ef41Sopenharmony_cishould never be used outside of testing. 9721cb0ef41Sopenharmony_ci 9731cb0ef41Sopenharmony_ciDuring shutdown of the process or worker threads destructors are not called 9741cb0ef41Sopenharmony_ciby the JS engine. Therefore it's the responsibility of the user to track 9751cb0ef41Sopenharmony_cithese objects and ensure proper destruction to avoid resource leaks. 9761cb0ef41Sopenharmony_ci 9771cb0ef41Sopenharmony_ci### Factory of wrapped objects 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_ciAlternatively, it is possible to use a factory pattern to avoid explicitly 9801cb0ef41Sopenharmony_cicreating object instances using the JavaScript `new` operator: 9811cb0ef41Sopenharmony_ci 9821cb0ef41Sopenharmony_ci```js 9831cb0ef41Sopenharmony_ciconst obj = addon.createObject(); 9841cb0ef41Sopenharmony_ci// instead of: 9851cb0ef41Sopenharmony_ci// const obj = new addon.Object(); 9861cb0ef41Sopenharmony_ci``` 9871cb0ef41Sopenharmony_ci 9881cb0ef41Sopenharmony_ciFirst, the `createObject()` method is implemented in `addon.cc`: 9891cb0ef41Sopenharmony_ci 9901cb0ef41Sopenharmony_ci```cpp 9911cb0ef41Sopenharmony_ci// addon.cc 9921cb0ef41Sopenharmony_ci#include <node.h> 9931cb0ef41Sopenharmony_ci#include "myobject.h" 9941cb0ef41Sopenharmony_ci 9951cb0ef41Sopenharmony_cinamespace demo { 9961cb0ef41Sopenharmony_ci 9971cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 9981cb0ef41Sopenharmony_ciusing v8::Isolate; 9991cb0ef41Sopenharmony_ciusing v8::Local; 10001cb0ef41Sopenharmony_ciusing v8::Object; 10011cb0ef41Sopenharmony_ciusing v8::String; 10021cb0ef41Sopenharmony_ciusing v8::Value; 10031cb0ef41Sopenharmony_ci 10041cb0ef41Sopenharmony_civoid CreateObject(const FunctionCallbackInfo<Value>& args) { 10051cb0ef41Sopenharmony_ci MyObject::NewInstance(args); 10061cb0ef41Sopenharmony_ci} 10071cb0ef41Sopenharmony_ci 10081cb0ef41Sopenharmony_civoid InitAll(Local<Object> exports, Local<Object> module) { 10091cb0ef41Sopenharmony_ci MyObject::Init(exports->GetIsolate()); 10101cb0ef41Sopenharmony_ci 10111cb0ef41Sopenharmony_ci NODE_SET_METHOD(module, "exports", CreateObject); 10121cb0ef41Sopenharmony_ci} 10131cb0ef41Sopenharmony_ci 10141cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, InitAll) 10151cb0ef41Sopenharmony_ci 10161cb0ef41Sopenharmony_ci} // namespace demo 10171cb0ef41Sopenharmony_ci``` 10181cb0ef41Sopenharmony_ci 10191cb0ef41Sopenharmony_ciIn `myobject.h`, the static method `NewInstance()` is added to handle 10201cb0ef41Sopenharmony_ciinstantiating the object. This method takes the place of using `new` in 10211cb0ef41Sopenharmony_ciJavaScript: 10221cb0ef41Sopenharmony_ci 10231cb0ef41Sopenharmony_ci```cpp 10241cb0ef41Sopenharmony_ci// myobject.h 10251cb0ef41Sopenharmony_ci#ifndef MYOBJECT_H 10261cb0ef41Sopenharmony_ci#define MYOBJECT_H 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci#include <node.h> 10291cb0ef41Sopenharmony_ci#include <node_object_wrap.h> 10301cb0ef41Sopenharmony_ci 10311cb0ef41Sopenharmony_cinamespace demo { 10321cb0ef41Sopenharmony_ci 10331cb0ef41Sopenharmony_ciclass MyObject : public node::ObjectWrap { 10341cb0ef41Sopenharmony_ci public: 10351cb0ef41Sopenharmony_ci static void Init(v8::Isolate* isolate); 10361cb0ef41Sopenharmony_ci static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args); 10371cb0ef41Sopenharmony_ci 10381cb0ef41Sopenharmony_ci private: 10391cb0ef41Sopenharmony_ci explicit MyObject(double value = 0); 10401cb0ef41Sopenharmony_ci ~MyObject(); 10411cb0ef41Sopenharmony_ci 10421cb0ef41Sopenharmony_ci static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 10431cb0ef41Sopenharmony_ci static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args); 10441cb0ef41Sopenharmony_ci static v8::Global<v8::Function> constructor; 10451cb0ef41Sopenharmony_ci double value_; 10461cb0ef41Sopenharmony_ci}; 10471cb0ef41Sopenharmony_ci 10481cb0ef41Sopenharmony_ci} // namespace demo 10491cb0ef41Sopenharmony_ci 10501cb0ef41Sopenharmony_ci#endif 10511cb0ef41Sopenharmony_ci``` 10521cb0ef41Sopenharmony_ci 10531cb0ef41Sopenharmony_ciThe implementation in `myobject.cc` is similar to the previous example: 10541cb0ef41Sopenharmony_ci 10551cb0ef41Sopenharmony_ci```cpp 10561cb0ef41Sopenharmony_ci// myobject.cc 10571cb0ef41Sopenharmony_ci#include <node.h> 10581cb0ef41Sopenharmony_ci#include "myobject.h" 10591cb0ef41Sopenharmony_ci 10601cb0ef41Sopenharmony_cinamespace demo { 10611cb0ef41Sopenharmony_ci 10621cb0ef41Sopenharmony_ciusing node::AddEnvironmentCleanupHook; 10631cb0ef41Sopenharmony_ciusing v8::Context; 10641cb0ef41Sopenharmony_ciusing v8::Function; 10651cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 10661cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 10671cb0ef41Sopenharmony_ciusing v8::Global; 10681cb0ef41Sopenharmony_ciusing v8::Isolate; 10691cb0ef41Sopenharmony_ciusing v8::Local; 10701cb0ef41Sopenharmony_ciusing v8::Number; 10711cb0ef41Sopenharmony_ciusing v8::Object; 10721cb0ef41Sopenharmony_ciusing v8::String; 10731cb0ef41Sopenharmony_ciusing v8::Value; 10741cb0ef41Sopenharmony_ci 10751cb0ef41Sopenharmony_ci// Warning! This is not thread-safe, this addon cannot be used for worker 10761cb0ef41Sopenharmony_ci// threads. 10771cb0ef41Sopenharmony_ciGlobal<Function> MyObject::constructor; 10781cb0ef41Sopenharmony_ci 10791cb0ef41Sopenharmony_ciMyObject::MyObject(double value) : value_(value) { 10801cb0ef41Sopenharmony_ci} 10811cb0ef41Sopenharmony_ci 10821cb0ef41Sopenharmony_ciMyObject::~MyObject() { 10831cb0ef41Sopenharmony_ci} 10841cb0ef41Sopenharmony_ci 10851cb0ef41Sopenharmony_civoid MyObject::Init(Isolate* isolate) { 10861cb0ef41Sopenharmony_ci // Prepare constructor template 10871cb0ef41Sopenharmony_ci Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); 10881cb0ef41Sopenharmony_ci tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); 10891cb0ef41Sopenharmony_ci tpl->InstanceTemplate()->SetInternalFieldCount(1); 10901cb0ef41Sopenharmony_ci 10911cb0ef41Sopenharmony_ci // Prototype 10921cb0ef41Sopenharmony_ci NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); 10931cb0ef41Sopenharmony_ci 10941cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 10951cb0ef41Sopenharmony_ci constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); 10961cb0ef41Sopenharmony_ci 10971cb0ef41Sopenharmony_ci AddEnvironmentCleanupHook(isolate, [](void*) { 10981cb0ef41Sopenharmony_ci constructor.Reset(); 10991cb0ef41Sopenharmony_ci }, nullptr); 11001cb0ef41Sopenharmony_ci} 11011cb0ef41Sopenharmony_ci 11021cb0ef41Sopenharmony_civoid MyObject::New(const FunctionCallbackInfo<Value>& args) { 11031cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 11041cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 11051cb0ef41Sopenharmony_ci 11061cb0ef41Sopenharmony_ci if (args.IsConstructCall()) { 11071cb0ef41Sopenharmony_ci // Invoked as constructor: `new MyObject(...)` 11081cb0ef41Sopenharmony_ci double value = args[0]->IsUndefined() ? 11091cb0ef41Sopenharmony_ci 0 : args[0]->NumberValue(context).FromMaybe(0); 11101cb0ef41Sopenharmony_ci MyObject* obj = new MyObject(value); 11111cb0ef41Sopenharmony_ci obj->Wrap(args.This()); 11121cb0ef41Sopenharmony_ci args.GetReturnValue().Set(args.This()); 11131cb0ef41Sopenharmony_ci } else { 11141cb0ef41Sopenharmony_ci // Invoked as plain function `MyObject(...)`, turn into construct call. 11151cb0ef41Sopenharmony_ci const int argc = 1; 11161cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { args[0] }; 11171cb0ef41Sopenharmony_ci Local<Function> cons = Local<Function>::New(isolate, constructor); 11181cb0ef41Sopenharmony_ci Local<Object> instance = 11191cb0ef41Sopenharmony_ci cons->NewInstance(context, argc, argv).ToLocalChecked(); 11201cb0ef41Sopenharmony_ci args.GetReturnValue().Set(instance); 11211cb0ef41Sopenharmony_ci } 11221cb0ef41Sopenharmony_ci} 11231cb0ef41Sopenharmony_ci 11241cb0ef41Sopenharmony_civoid MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) { 11251cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 11261cb0ef41Sopenharmony_ci 11271cb0ef41Sopenharmony_ci const unsigned argc = 1; 11281cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { args[0] }; 11291cb0ef41Sopenharmony_ci Local<Function> cons = Local<Function>::New(isolate, constructor); 11301cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 11311cb0ef41Sopenharmony_ci Local<Object> instance = 11321cb0ef41Sopenharmony_ci cons->NewInstance(context, argc, argv).ToLocalChecked(); 11331cb0ef41Sopenharmony_ci 11341cb0ef41Sopenharmony_ci args.GetReturnValue().Set(instance); 11351cb0ef41Sopenharmony_ci} 11361cb0ef41Sopenharmony_ci 11371cb0ef41Sopenharmony_civoid MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) { 11381cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 11391cb0ef41Sopenharmony_ci 11401cb0ef41Sopenharmony_ci MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder()); 11411cb0ef41Sopenharmony_ci obj->value_ += 1; 11421cb0ef41Sopenharmony_ci 11431cb0ef41Sopenharmony_ci args.GetReturnValue().Set(Number::New(isolate, obj->value_)); 11441cb0ef41Sopenharmony_ci} 11451cb0ef41Sopenharmony_ci 11461cb0ef41Sopenharmony_ci} // namespace demo 11471cb0ef41Sopenharmony_ci``` 11481cb0ef41Sopenharmony_ci 11491cb0ef41Sopenharmony_ciOnce again, to build this example, the `myobject.cc` file must be added to the 11501cb0ef41Sopenharmony_ci`binding.gyp`: 11511cb0ef41Sopenharmony_ci 11521cb0ef41Sopenharmony_ci```json 11531cb0ef41Sopenharmony_ci{ 11541cb0ef41Sopenharmony_ci "targets": [ 11551cb0ef41Sopenharmony_ci { 11561cb0ef41Sopenharmony_ci "target_name": "addon", 11571cb0ef41Sopenharmony_ci "sources": [ 11581cb0ef41Sopenharmony_ci "addon.cc", 11591cb0ef41Sopenharmony_ci "myobject.cc" 11601cb0ef41Sopenharmony_ci ] 11611cb0ef41Sopenharmony_ci } 11621cb0ef41Sopenharmony_ci ] 11631cb0ef41Sopenharmony_ci} 11641cb0ef41Sopenharmony_ci``` 11651cb0ef41Sopenharmony_ci 11661cb0ef41Sopenharmony_ciTest it with: 11671cb0ef41Sopenharmony_ci 11681cb0ef41Sopenharmony_ci```js 11691cb0ef41Sopenharmony_ci// test.js 11701cb0ef41Sopenharmony_ciconst createObject = require('./build/Release/addon'); 11711cb0ef41Sopenharmony_ci 11721cb0ef41Sopenharmony_ciconst obj = createObject(10); 11731cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 11741cb0ef41Sopenharmony_ci// Prints: 11 11751cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 11761cb0ef41Sopenharmony_ci// Prints: 12 11771cb0ef41Sopenharmony_ciconsole.log(obj.plusOne()); 11781cb0ef41Sopenharmony_ci// Prints: 13 11791cb0ef41Sopenharmony_ci 11801cb0ef41Sopenharmony_ciconst obj2 = createObject(20); 11811cb0ef41Sopenharmony_ciconsole.log(obj2.plusOne()); 11821cb0ef41Sopenharmony_ci// Prints: 21 11831cb0ef41Sopenharmony_ciconsole.log(obj2.plusOne()); 11841cb0ef41Sopenharmony_ci// Prints: 22 11851cb0ef41Sopenharmony_ciconsole.log(obj2.plusOne()); 11861cb0ef41Sopenharmony_ci// Prints: 23 11871cb0ef41Sopenharmony_ci``` 11881cb0ef41Sopenharmony_ci 11891cb0ef41Sopenharmony_ci### Passing wrapped objects around 11901cb0ef41Sopenharmony_ci 11911cb0ef41Sopenharmony_ciIn addition to wrapping and returning C++ objects, it is possible to pass 11921cb0ef41Sopenharmony_ciwrapped objects around by unwrapping them with the Node.js helper function 11931cb0ef41Sopenharmony_ci`node::ObjectWrap::Unwrap`. The following examples shows a function `add()` 11941cb0ef41Sopenharmony_cithat can take two `MyObject` objects as input arguments: 11951cb0ef41Sopenharmony_ci 11961cb0ef41Sopenharmony_ci```cpp 11971cb0ef41Sopenharmony_ci// addon.cc 11981cb0ef41Sopenharmony_ci#include <node.h> 11991cb0ef41Sopenharmony_ci#include <node_object_wrap.h> 12001cb0ef41Sopenharmony_ci#include "myobject.h" 12011cb0ef41Sopenharmony_ci 12021cb0ef41Sopenharmony_cinamespace demo { 12031cb0ef41Sopenharmony_ci 12041cb0ef41Sopenharmony_ciusing v8::Context; 12051cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 12061cb0ef41Sopenharmony_ciusing v8::Isolate; 12071cb0ef41Sopenharmony_ciusing v8::Local; 12081cb0ef41Sopenharmony_ciusing v8::Number; 12091cb0ef41Sopenharmony_ciusing v8::Object; 12101cb0ef41Sopenharmony_ciusing v8::String; 12111cb0ef41Sopenharmony_ciusing v8::Value; 12121cb0ef41Sopenharmony_ci 12131cb0ef41Sopenharmony_civoid CreateObject(const FunctionCallbackInfo<Value>& args) { 12141cb0ef41Sopenharmony_ci MyObject::NewInstance(args); 12151cb0ef41Sopenharmony_ci} 12161cb0ef41Sopenharmony_ci 12171cb0ef41Sopenharmony_civoid Add(const FunctionCallbackInfo<Value>& args) { 12181cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 12191cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 12201cb0ef41Sopenharmony_ci 12211cb0ef41Sopenharmony_ci MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>( 12221cb0ef41Sopenharmony_ci args[0]->ToObject(context).ToLocalChecked()); 12231cb0ef41Sopenharmony_ci MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>( 12241cb0ef41Sopenharmony_ci args[1]->ToObject(context).ToLocalChecked()); 12251cb0ef41Sopenharmony_ci 12261cb0ef41Sopenharmony_ci double sum = obj1->value() + obj2->value(); 12271cb0ef41Sopenharmony_ci args.GetReturnValue().Set(Number::New(isolate, sum)); 12281cb0ef41Sopenharmony_ci} 12291cb0ef41Sopenharmony_ci 12301cb0ef41Sopenharmony_civoid InitAll(Local<Object> exports) { 12311cb0ef41Sopenharmony_ci MyObject::Init(exports->GetIsolate()); 12321cb0ef41Sopenharmony_ci 12331cb0ef41Sopenharmony_ci NODE_SET_METHOD(exports, "createObject", CreateObject); 12341cb0ef41Sopenharmony_ci NODE_SET_METHOD(exports, "add", Add); 12351cb0ef41Sopenharmony_ci} 12361cb0ef41Sopenharmony_ci 12371cb0ef41Sopenharmony_ciNODE_MODULE(NODE_GYP_MODULE_NAME, InitAll) 12381cb0ef41Sopenharmony_ci 12391cb0ef41Sopenharmony_ci} // namespace demo 12401cb0ef41Sopenharmony_ci``` 12411cb0ef41Sopenharmony_ci 12421cb0ef41Sopenharmony_ciIn `myobject.h`, a new public method is added to allow access to private values 12431cb0ef41Sopenharmony_ciafter unwrapping the object. 12441cb0ef41Sopenharmony_ci 12451cb0ef41Sopenharmony_ci```cpp 12461cb0ef41Sopenharmony_ci// myobject.h 12471cb0ef41Sopenharmony_ci#ifndef MYOBJECT_H 12481cb0ef41Sopenharmony_ci#define MYOBJECT_H 12491cb0ef41Sopenharmony_ci 12501cb0ef41Sopenharmony_ci#include <node.h> 12511cb0ef41Sopenharmony_ci#include <node_object_wrap.h> 12521cb0ef41Sopenharmony_ci 12531cb0ef41Sopenharmony_cinamespace demo { 12541cb0ef41Sopenharmony_ci 12551cb0ef41Sopenharmony_ciclass MyObject : public node::ObjectWrap { 12561cb0ef41Sopenharmony_ci public: 12571cb0ef41Sopenharmony_ci static void Init(v8::Isolate* isolate); 12581cb0ef41Sopenharmony_ci static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args); 12591cb0ef41Sopenharmony_ci inline double value() const { return value_; } 12601cb0ef41Sopenharmony_ci 12611cb0ef41Sopenharmony_ci private: 12621cb0ef41Sopenharmony_ci explicit MyObject(double value = 0); 12631cb0ef41Sopenharmony_ci ~MyObject(); 12641cb0ef41Sopenharmony_ci 12651cb0ef41Sopenharmony_ci static void New(const v8::FunctionCallbackInfo<v8::Value>& args); 12661cb0ef41Sopenharmony_ci static v8::Global<v8::Function> constructor; 12671cb0ef41Sopenharmony_ci double value_; 12681cb0ef41Sopenharmony_ci}; 12691cb0ef41Sopenharmony_ci 12701cb0ef41Sopenharmony_ci} // namespace demo 12711cb0ef41Sopenharmony_ci 12721cb0ef41Sopenharmony_ci#endif 12731cb0ef41Sopenharmony_ci``` 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ciThe implementation of `myobject.cc` is similar to before: 12761cb0ef41Sopenharmony_ci 12771cb0ef41Sopenharmony_ci```cpp 12781cb0ef41Sopenharmony_ci// myobject.cc 12791cb0ef41Sopenharmony_ci#include <node.h> 12801cb0ef41Sopenharmony_ci#include "myobject.h" 12811cb0ef41Sopenharmony_ci 12821cb0ef41Sopenharmony_cinamespace demo { 12831cb0ef41Sopenharmony_ci 12841cb0ef41Sopenharmony_ciusing node::AddEnvironmentCleanupHook; 12851cb0ef41Sopenharmony_ciusing v8::Context; 12861cb0ef41Sopenharmony_ciusing v8::Function; 12871cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 12881cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 12891cb0ef41Sopenharmony_ciusing v8::Global; 12901cb0ef41Sopenharmony_ciusing v8::Isolate; 12911cb0ef41Sopenharmony_ciusing v8::Local; 12921cb0ef41Sopenharmony_ciusing v8::Object; 12931cb0ef41Sopenharmony_ciusing v8::String; 12941cb0ef41Sopenharmony_ciusing v8::Value; 12951cb0ef41Sopenharmony_ci 12961cb0ef41Sopenharmony_ci// Warning! This is not thread-safe, this addon cannot be used for worker 12971cb0ef41Sopenharmony_ci// threads. 12981cb0ef41Sopenharmony_ciGlobal<Function> MyObject::constructor; 12991cb0ef41Sopenharmony_ci 13001cb0ef41Sopenharmony_ciMyObject::MyObject(double value) : value_(value) { 13011cb0ef41Sopenharmony_ci} 13021cb0ef41Sopenharmony_ci 13031cb0ef41Sopenharmony_ciMyObject::~MyObject() { 13041cb0ef41Sopenharmony_ci} 13051cb0ef41Sopenharmony_ci 13061cb0ef41Sopenharmony_civoid MyObject::Init(Isolate* isolate) { 13071cb0ef41Sopenharmony_ci // Prepare constructor template 13081cb0ef41Sopenharmony_ci Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New); 13091cb0ef41Sopenharmony_ci tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked()); 13101cb0ef41Sopenharmony_ci tpl->InstanceTemplate()->SetInternalFieldCount(1); 13111cb0ef41Sopenharmony_ci 13121cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 13131cb0ef41Sopenharmony_ci constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); 13141cb0ef41Sopenharmony_ci 13151cb0ef41Sopenharmony_ci AddEnvironmentCleanupHook(isolate, [](void*) { 13161cb0ef41Sopenharmony_ci constructor.Reset(); 13171cb0ef41Sopenharmony_ci }, nullptr); 13181cb0ef41Sopenharmony_ci} 13191cb0ef41Sopenharmony_ci 13201cb0ef41Sopenharmony_civoid MyObject::New(const FunctionCallbackInfo<Value>& args) { 13211cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 13221cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 13231cb0ef41Sopenharmony_ci 13241cb0ef41Sopenharmony_ci if (args.IsConstructCall()) { 13251cb0ef41Sopenharmony_ci // Invoked as constructor: `new MyObject(...)` 13261cb0ef41Sopenharmony_ci double value = args[0]->IsUndefined() ? 13271cb0ef41Sopenharmony_ci 0 : args[0]->NumberValue(context).FromMaybe(0); 13281cb0ef41Sopenharmony_ci MyObject* obj = new MyObject(value); 13291cb0ef41Sopenharmony_ci obj->Wrap(args.This()); 13301cb0ef41Sopenharmony_ci args.GetReturnValue().Set(args.This()); 13311cb0ef41Sopenharmony_ci } else { 13321cb0ef41Sopenharmony_ci // Invoked as plain function `MyObject(...)`, turn into construct call. 13331cb0ef41Sopenharmony_ci const int argc = 1; 13341cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { args[0] }; 13351cb0ef41Sopenharmony_ci Local<Function> cons = Local<Function>::New(isolate, constructor); 13361cb0ef41Sopenharmony_ci Local<Object> instance = 13371cb0ef41Sopenharmony_ci cons->NewInstance(context, argc, argv).ToLocalChecked(); 13381cb0ef41Sopenharmony_ci args.GetReturnValue().Set(instance); 13391cb0ef41Sopenharmony_ci } 13401cb0ef41Sopenharmony_ci} 13411cb0ef41Sopenharmony_ci 13421cb0ef41Sopenharmony_civoid MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) { 13431cb0ef41Sopenharmony_ci Isolate* isolate = args.GetIsolate(); 13441cb0ef41Sopenharmony_ci 13451cb0ef41Sopenharmony_ci const unsigned argc = 1; 13461cb0ef41Sopenharmony_ci Local<Value> argv[argc] = { args[0] }; 13471cb0ef41Sopenharmony_ci Local<Function> cons = Local<Function>::New(isolate, constructor); 13481cb0ef41Sopenharmony_ci Local<Context> context = isolate->GetCurrentContext(); 13491cb0ef41Sopenharmony_ci Local<Object> instance = 13501cb0ef41Sopenharmony_ci cons->NewInstance(context, argc, argv).ToLocalChecked(); 13511cb0ef41Sopenharmony_ci 13521cb0ef41Sopenharmony_ci args.GetReturnValue().Set(instance); 13531cb0ef41Sopenharmony_ci} 13541cb0ef41Sopenharmony_ci 13551cb0ef41Sopenharmony_ci} // namespace demo 13561cb0ef41Sopenharmony_ci``` 13571cb0ef41Sopenharmony_ci 13581cb0ef41Sopenharmony_ciTest it with: 13591cb0ef41Sopenharmony_ci 13601cb0ef41Sopenharmony_ci```js 13611cb0ef41Sopenharmony_ci// test.js 13621cb0ef41Sopenharmony_ciconst addon = require('./build/Release/addon'); 13631cb0ef41Sopenharmony_ci 13641cb0ef41Sopenharmony_ciconst obj1 = addon.createObject(10); 13651cb0ef41Sopenharmony_ciconst obj2 = addon.createObject(20); 13661cb0ef41Sopenharmony_ciconst result = addon.add(obj1, obj2); 13671cb0ef41Sopenharmony_ci 13681cb0ef41Sopenharmony_ciconsole.log(result); 13691cb0ef41Sopenharmony_ci// Prints: 30 13701cb0ef41Sopenharmony_ci``` 13711cb0ef41Sopenharmony_ci 13721cb0ef41Sopenharmony_ci[Electron]: https://electronjs.org/ 13731cb0ef41Sopenharmony_ci[Embedder's Guide]: https://v8.dev/docs/embed 13741cb0ef41Sopenharmony_ci[Linking to libraries included with Node.js]: #linking-to-libraries-included-with-nodejs 13751cb0ef41Sopenharmony_ci[Native Abstractions for Node.js]: https://github.com/nodejs/nan 13761cb0ef41Sopenharmony_ci[V8]: https://v8.dev/ 13771cb0ef41Sopenharmony_ci[`Worker`]: worker_threads.md#class-worker 13781cb0ef41Sopenharmony_ci[bindings]: https://github.com/TooTallNate/node-bindings 13791cb0ef41Sopenharmony_ci[download]: https://github.com/nodejs/node-addon-examples 13801cb0ef41Sopenharmony_ci[examples]: https://github.com/nodejs/nan/tree/HEAD/examples/ 13811cb0ef41Sopenharmony_ci[implementation considerations]: n-api.md#implications-of-abi-stability 13821cb0ef41Sopenharmony_ci[installation instructions]: https://github.com/nodejs/node-gyp#installation 13831cb0ef41Sopenharmony_ci[libuv]: https://github.com/libuv/libuv 13841cb0ef41Sopenharmony_ci[node-gyp]: https://github.com/nodejs/node-gyp 13851cb0ef41Sopenharmony_ci[require]: modules.md#requireid 13861cb0ef41Sopenharmony_ci[v8-docs]: https://v8docs.nodesource.com/ 1387