xref: /third_party/node/doc/api/addons.md (revision 1cb0ef41)
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