• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# C++ addons
2
3<!--introduced_in=v0.10.0-->
4
5<!-- type=misc -->
6
7_Addons_ are dynamically-linked shared objects written in C++. The
8[`require()`][require] function can load addons as ordinary Node.js modules.
9Addons provide an interface between JavaScript and C/C++ libraries.
10
11There are three options for implementing addons: Node-API, nan, or direct
12use of internal V8, libuv, and Node.js libraries. Unless there is a need for
13direct access to functionality which is not exposed by Node-API, use Node-API.
14Refer to [C/C++ addons with Node-API](n-api.md) for more information on
15Node-API.
16
17When not using Node-API, implementing addons is complicated,
18involving knowledge of several components and APIs:
19
20* [V8][]: the C++ library Node.js uses to provide the
21  JavaScript implementation. V8 provides the mechanisms for creating objects,
22  calling functions, etc. V8's API is documented mostly in the
23  `v8.h` header file (`deps/v8/include/v8.h` in the Node.js source
24  tree), which is also available [online][v8-docs].
25
26* [libuv][]: The C library that implements the Node.js event loop, its worker
27  threads and all of the asynchronous behaviors of the platform. It also
28  serves as a cross-platform abstraction library, giving easy, POSIX-like
29  access across all major operating systems to many common system tasks, such
30  as interacting with the file system, sockets, timers, and system events. libuv
31  also provides a threading abstraction similar to POSIX threads for
32  more sophisticated asynchronous addons that need to move beyond the
33  standard event loop. Addon authors should
34  avoid blocking the event loop with I/O or other time-intensive tasks by
35  offloading work via libuv to non-blocking system operations, worker threads,
36  or a custom use of libuv threads.
37
38* Internal Node.js libraries. Node.js itself exports C++ APIs that addons can
39  use, the most important of which is the `node::ObjectWrap` class.
40
41* Node.js includes other statically linked libraries including OpenSSL. These
42  other libraries are located in the `deps/` directory in the Node.js source
43  tree. Only the libuv, OpenSSL, V8, and zlib symbols are purposefully
44  re-exported by Node.js and may be used to various extents by addons. See
45  [Linking to libraries included with Node.js][] for additional information.
46
47All of the following examples are available for [download][] and may
48be used as the starting-point for an addon.
49
50## Hello world
51
52This "Hello world" example is a simple addon, written in C++, that is the
53equivalent of the following JavaScript code:
54
55```js
56module.exports.hello = () => 'world';
57```
58
59First, create the file `hello.cc`:
60
61```cpp
62// hello.cc
63#include <node.h>
64
65namespace demo {
66
67using v8::FunctionCallbackInfo;
68using v8::Isolate;
69using v8::Local;
70using v8::Object;
71using v8::String;
72using v8::Value;
73
74void Method(const FunctionCallbackInfo<Value>& args) {
75  Isolate* isolate = args.GetIsolate();
76  args.GetReturnValue().Set(String::NewFromUtf8(
77      isolate, "world").ToLocalChecked());
78}
79
80void Initialize(Local<Object> exports) {
81  NODE_SET_METHOD(exports, "hello", Method);
82}
83
84NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
85
86}  // namespace demo
87```
88
89All Node.js addons must export an initialization function following
90the pattern:
91
92```cpp
93void Initialize(Local<Object> exports);
94NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
95```
96
97There is no semi-colon after `NODE_MODULE` as it's not a function (see
98`node.h`).
99
100The `module_name` must match the filename of the final binary (excluding
101the `.node` suffix).
102
103In the `hello.cc` example, then, the initialization function is `Initialize`
104and the addon module name is `addon`.
105
106When building addons with `node-gyp`, using the macro `NODE_GYP_MODULE_NAME` as
107the first parameter of `NODE_MODULE()` will ensure that the name of the final
108binary will be passed to `NODE_MODULE()`.
109
110Addons defined with `NODE_MODULE()` can not be loaded in multiple contexts or
111multiple threads at the same time.
112
113### Context-aware addons
114
115There are environments in which Node.js addons may need to be loaded multiple
116times in multiple contexts. For example, the [Electron][] runtime runs multiple
117instances of Node.js in a single process. Each instance will have its own
118`require()` cache, and thus each instance will need a native addon to behave
119correctly when loaded via `require()`. This means that the addon
120must support multiple initializations.
121
122A context-aware addon can be constructed by using the macro
123`NODE_MODULE_INITIALIZER`, which expands to the name of a function which Node.js
124will expect to find when it loads an addon. An addon can thus be initialized as
125in the following example:
126
127```cpp
128using namespace v8;
129
130extern "C" NODE_MODULE_EXPORT void
131NODE_MODULE_INITIALIZER(Local<Object> exports,
132                        Local<Value> module,
133                        Local<Context> context) {
134  /* Perform addon initialization steps here. */
135}
136```
137
138Another option is to use the macro `NODE_MODULE_INIT()`, which will also
139construct a context-aware addon. Unlike `NODE_MODULE()`, which is used to
140construct an addon around a given addon initializer function,
141`NODE_MODULE_INIT()` serves as the declaration of such an initializer to be
142followed by a function body.
143
144The following three variables may be used inside the function body following an
145invocation of `NODE_MODULE_INIT()`:
146
147* `Local<Object> exports`,
148* `Local<Value> module`, and
149* `Local<Context> context`
150
151The choice to build a context-aware addon carries with it the responsibility of
152carefully managing global static data. Since the addon may be loaded multiple
153times, potentially even from different threads, any global static data stored
154in the addon must be properly protected, and must not contain any persistent
155references to JavaScript objects. The reason for this is that JavaScript
156objects are only valid in one context, and will likely cause a crash when
157accessed from the wrong context or from a different thread than the one on which
158they were created.
159
160The context-aware addon can be structured to avoid global static data by
161performing the following steps:
162
163* Define a class which will hold per-addon-instance data and which has a static
164  member of the form
165  ```cpp
166  static void DeleteInstance(void* data) {
167    // Cast `data` to an instance of the class and delete it.
168  }
169  ```
170* Heap-allocate an instance of this class in the addon initializer. This can be
171  accomplished using the `new` keyword.
172* Call `node::AddEnvironmentCleanupHook()`, passing it the above-created
173  instance and a pointer to `DeleteInstance()`. This will ensure the instance is
174  deleted when the environment is torn down.
175* Store the instance of the class in a `v8::External`, and
176* Pass the `v8::External` to all methods exposed to JavaScript by passing it
177  to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the
178  native-backed JavaScript functions. The third parameter of
179  `v8::FunctionTemplate::New()` or `v8::Function::New()`  accepts the
180  `v8::External` and makes it available in the native callback using the
181  `v8::FunctionCallbackInfo::Data()` method.
182
183This will ensure that the per-addon-instance data reaches each binding that can
184be called from JavaScript. The per-addon-instance data must also be passed into
185any asynchronous callbacks the addon may create.
186
187The following example illustrates the implementation of a context-aware addon:
188
189```cpp
190#include <node.h>
191
192using namespace v8;
193
194class AddonData {
195 public:
196  explicit AddonData(Isolate* isolate):
197      call_count(0) {
198    // Ensure this per-addon-instance data is deleted at environment cleanup.
199    node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this);
200  }
201
202  // Per-addon data.
203  int call_count;
204
205  static void DeleteInstance(void* data) {
206    delete static_cast<AddonData*>(data);
207  }
208};
209
210static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
211  // Retrieve the per-addon-instance data.
212  AddonData* data =
213      reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
214  data->call_count++;
215  info.GetReturnValue().Set((double)data->call_count);
216}
217
218// Initialize this addon to be context-aware.
219NODE_MODULE_INIT(/* exports, module, context */) {
220  Isolate* isolate = context->GetIsolate();
221
222  // Create a new instance of `AddonData` for this instance of the addon and
223  // tie its life cycle to that of the Node.js environment.
224  AddonData* data = new AddonData(isolate);
225
226  // Wrap the data in a `v8::External` so we can pass it to the method we
227  // expose.
228  Local<External> external = External::New(isolate, data);
229
230  // Expose the method `Method` to JavaScript, and make sure it receives the
231  // per-addon-instance data we created above by passing `external` as the
232  // third parameter to the `FunctionTemplate` constructor.
233  exports->Set(context,
234               String::NewFromUtf8(isolate, "method").ToLocalChecked(),
235               FunctionTemplate::New(isolate, Method, external)
236                  ->GetFunction(context).ToLocalChecked()).FromJust();
237}
238```
239
240#### Worker support
241
242<!-- YAML
243changes:
244  - version:
245    - v14.8.0
246    - v12.19.0
247    pr-url: https://github.com/nodejs/node/pull/34572
248    description: Cleanup hooks may now be asynchronous.
249-->
250
251In order to be loaded from multiple Node.js environments,
252such as a main thread and a Worker thread, an add-on needs to either:
253
254* Be an Node-API addon, or
255* Be declared as context-aware using `NODE_MODULE_INIT()` as described above
256
257In order to support [`Worker`][] threads, addons need to clean up any resources
258they may have allocated when such a thread exists. This can be achieved through
259the usage of the `AddEnvironmentCleanupHook()` function:
260
261```cpp
262void AddEnvironmentCleanupHook(v8::Isolate* isolate,
263                               void (*fun)(void* arg),
264                               void* arg);
265```
266
267This function adds a hook that will run before a given Node.js instance shuts
268down. If necessary, such hooks can be removed before they are run using
269`RemoveEnvironmentCleanupHook()`, which has the same signature. Callbacks are
270run in last-in first-out order.
271
272If necessary, there is an additional pair of `AddEnvironmentCleanupHook()`
273and `RemoveEnvironmentCleanupHook()` overloads, where the cleanup hook takes a
274callback function. This can be used for shutting down asynchronous resources,
275such as any libuv handles registered by the addon.
276
277The following `addon.cc` uses `AddEnvironmentCleanupHook`:
278
279```cpp
280// addon.cc
281#include <node.h>
282#include <assert.h>
283#include <stdlib.h>
284
285using node::AddEnvironmentCleanupHook;
286using v8::HandleScope;
287using v8::Isolate;
288using v8::Local;
289using v8::Object;
290
291// Note: In a real-world application, do not rely on static/global data.
292static char cookie[] = "yum yum";
293static int cleanup_cb1_called = 0;
294static int cleanup_cb2_called = 0;
295
296static void cleanup_cb1(void* arg) {
297  Isolate* isolate = static_cast<Isolate*>(arg);
298  HandleScope scope(isolate);
299  Local<Object> obj = Object::New(isolate);
300  assert(!obj.IsEmpty());  // assert VM is still alive
301  assert(obj->IsObject());
302  cleanup_cb1_called++;
303}
304
305static void cleanup_cb2(void* arg) {
306  assert(arg == static_cast<void*>(cookie));
307  cleanup_cb2_called++;
308}
309
310static void sanity_check(void*) {
311  assert(cleanup_cb1_called == 1);
312  assert(cleanup_cb2_called == 1);
313}
314
315// Initialize this addon to be context-aware.
316NODE_MODULE_INIT(/* exports, module, context */) {
317  Isolate* isolate = context->GetIsolate();
318
319  AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
320  AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
321  AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
322}
323```
324
325Test in JavaScript by running:
326
327```js
328// test.js
329require('./build/Release/addon');
330```
331
332### Building
333
334Once the source code has been written, it must be compiled into the binary
335`addon.node` file. To do so, create a file called `binding.gyp` in the
336top-level of the project describing the build configuration of the module
337using a JSON-like format. This file is used by [node-gyp][], a tool written
338specifically to compile Node.js addons.
339
340```json
341{
342  "targets": [
343    {
344      "target_name": "addon",
345      "sources": [ "hello.cc" ]
346    }
347  ]
348}
349```
350
351A version of the `node-gyp` utility is bundled and distributed with
352Node.js as part of `npm`. This version is not made directly available for
353developers to use and is intended only to support the ability to use the
354`npm install` command to compile and install addons. Developers who wish to
355use `node-gyp` directly can install it using the command
356`npm install -g node-gyp`. See the `node-gyp` [installation instructions][] for
357more information, including platform-specific requirements.
358
359Once the `binding.gyp` file has been created, use `node-gyp configure` to
360generate the appropriate project build files for the current platform. This
361will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file
362(on Windows) in the `build/` directory.
363
364Next, invoke the `node-gyp build` command to generate the compiled `addon.node`
365file. This will be put into the `build/Release/` directory.
366
367When using `npm install` to install a Node.js addon, npm uses its own bundled
368version of `node-gyp` to perform this same set of actions, generating a
369compiled version of the addon for the user's platform on demand.
370
371Once built, the binary addon can be used from within Node.js by pointing
372[`require()`][require] to the built `addon.node` module:
373
374```js
375// hello.js
376const addon = require('./build/Release/addon');
377
378console.log(addon.hello());
379// Prints: 'world'
380```
381
382Because the exact path to the compiled addon binary can vary depending on how
383it is compiled (i.e. sometimes it may be in `./build/Debug/`), addons can use
384the [bindings][] package to load the compiled module.
385
386While the `bindings` package implementation is more sophisticated in how it
387locates addon modules, it is essentially using a `try…catch` pattern similar to:
388
389```js
390try {
391  return require('./build/Release/addon.node');
392} catch (err) {
393  return require('./build/Debug/addon.node');
394}
395```
396
397### Linking to libraries included with Node.js
398
399Node.js uses statically linked libraries such as V8, libuv, and OpenSSL. All
400addons are required to link to V8 and may link to any of the other dependencies
401as well. Typically, this is as simple as including the appropriate
402`#include <...>` statements (e.g. `#include <v8.h>`) and `node-gyp` will locate
403the appropriate headers automatically. However, there are a few caveats to be
404aware of:
405
406* When `node-gyp` runs, it will detect the specific release version of Node.js
407  and download either the full source tarball or just the headers. If the full
408  source is downloaded, addons will have complete access to the full set of
409  Node.js dependencies. However, if only the Node.js headers are downloaded,
410  then only the symbols exported by Node.js will be available.
411
412* `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js
413  source image. Using this option, the addon will have access to the full set of
414  dependencies.
415
416### Loading addons using `require()`
417
418The filename extension of the compiled addon binary is `.node` (as opposed
419to `.dll` or `.so`). The [`require()`][require] function is written to look for
420files with the `.node` file extension and initialize those as dynamically-linked
421libraries.
422
423When calling [`require()`][require], the `.node` extension can usually be
424omitted and Node.js will still find and initialize the addon. One caveat,
425however, is that Node.js will first attempt to locate and load modules or
426JavaScript files that happen to share the same base name. For instance, if
427there is a file `addon.js` in the same directory as the binary `addon.node`,
428then [`require('addon')`][require] will give precedence to the `addon.js` file
429and load it instead.
430
431## Native abstractions for Node.js
432
433Each of the examples illustrated in this document directly use the
434Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed
435dramatically from one V8 release to the next (and one major Node.js release to
436the next). With each change, addons may need to be updated and recompiled in
437order to continue functioning. The Node.js release schedule is designed to
438minimize the frequency and impact of such changes but there is little that
439Node.js can do to ensure stability of the V8 APIs.
440
441The [Native Abstractions for Node.js][] (or `nan`) provide a set of tools that
442addon developers are recommended to use to keep compatibility between past and
443future releases of V8 and Node.js. See the `nan` [examples][] for an
444illustration of how it can be used.
445
446## Node-API
447
448> Stability: 2 - Stable
449
450Node-API is an API for building native addons. It is independent from
451the underlying JavaScript runtime (e.g. V8) and is maintained as part of
452Node.js itself. This API will be Application Binary Interface (ABI) stable
453across versions of Node.js. It is intended to insulate addons from
454changes in the underlying JavaScript engine and allow modules
455compiled for one version to run on later versions of Node.js without
456recompilation. Addons are built/packaged with the same approach/tools
457outlined in this document (node-gyp, etc.). The only difference is the
458set of APIs that are used by the native code. Instead of using the V8
459or [Native Abstractions for Node.js][] APIs, the functions available
460in the Node-API are used.
461
462Creating and maintaining an addon that benefits from the ABI stability
463provided by Node-API carries with it certain
464[implementation considerations][].
465
466To use Node-API in the above "Hello world" example, replace the content of
467`hello.cc` with the following. All other instructions remain the same.
468
469```cpp
470// hello.cc using Node-API
471#include <node_api.h>
472
473namespace demo {
474
475napi_value Method(napi_env env, napi_callback_info args) {
476  napi_value greeting;
477  napi_status status;
478
479  status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
480  if (status != napi_ok) return nullptr;
481  return greeting;
482}
483
484napi_value init(napi_env env, napi_value exports) {
485  napi_status status;
486  napi_value fn;
487
488  status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
489  if (status != napi_ok) return nullptr;
490
491  status = napi_set_named_property(env, exports, "hello", fn);
492  if (status != napi_ok) return nullptr;
493  return exports;
494}
495
496NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
497
498}  // namespace demo
499```
500
501The functions available and how to use them are documented in
502[C/C++ addons with Node-API](n-api.md).
503
504## Addon examples
505
506Following are some example addons intended to help developers get started. The
507examples use the V8 APIs. Refer to the online [V8 reference][v8-docs]
508for help with the various V8 calls, and V8's [Embedder's Guide][] for an
509explanation of several concepts used such as handles, scopes, function
510templates, etc.
511
512Each of these examples using the following `binding.gyp` file:
513
514```json
515{
516  "targets": [
517    {
518      "target_name": "addon",
519      "sources": [ "addon.cc" ]
520    }
521  ]
522}
523```
524
525In cases where there is more than one `.cc` file, simply add the additional
526filename to the `sources` array:
527
528```json
529"sources": ["addon.cc", "myexample.cc"]
530```
531
532Once the `binding.gyp` file is ready, the example addons can be configured and
533built using `node-gyp`:
534
535```console
536$ node-gyp configure build
537```
538
539### Function arguments
540
541Addons will typically expose objects and functions that can be accessed from
542JavaScript running within Node.js. When functions are invoked from JavaScript,
543the input arguments and return value must be mapped to and from the C/C++
544code.
545
546The following example illustrates how to read function arguments passed from
547JavaScript and how to return a result:
548
549```cpp
550// addon.cc
551#include <node.h>
552
553namespace demo {
554
555using v8::Exception;
556using v8::FunctionCallbackInfo;
557using v8::Isolate;
558using v8::Local;
559using v8::Number;
560using v8::Object;
561using v8::String;
562using v8::Value;
563
564// This is the implementation of the "add" method
565// Input arguments are passed using the
566// const FunctionCallbackInfo<Value>& args struct
567void Add(const FunctionCallbackInfo<Value>& args) {
568  Isolate* isolate = args.GetIsolate();
569
570  // Check the number of arguments passed.
571  if (args.Length() < 2) {
572    // Throw an Error that is passed back to JavaScript
573    isolate->ThrowException(Exception::TypeError(
574        String::NewFromUtf8(isolate,
575                            "Wrong number of arguments").ToLocalChecked()));
576    return;
577  }
578
579  // Check the argument types
580  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
581    isolate->ThrowException(Exception::TypeError(
582        String::NewFromUtf8(isolate,
583                            "Wrong arguments").ToLocalChecked()));
584    return;
585  }
586
587  // Perform the operation
588  double value =
589      args[0].As<Number>()->Value() + args[1].As<Number>()->Value();
590  Local<Number> num = Number::New(isolate, value);
591
592  // Set the return value (using the passed in
593  // FunctionCallbackInfo<Value>&)
594  args.GetReturnValue().Set(num);
595}
596
597void Init(Local<Object> exports) {
598  NODE_SET_METHOD(exports, "add", Add);
599}
600
601NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
602
603}  // namespace demo
604```
605
606Once compiled, the example addon can be required and used from within Node.js:
607
608```js
609// test.js
610const addon = require('./build/Release/addon');
611
612console.log('This should be eight:', addon.add(3, 5));
613```
614
615### Callbacks
616
617It is common practice within addons to pass JavaScript functions to a C++
618function and execute them from there. The following example illustrates how
619to invoke such callbacks:
620
621```cpp
622// addon.cc
623#include <node.h>
624
625namespace demo {
626
627using v8::Context;
628using v8::Function;
629using v8::FunctionCallbackInfo;
630using v8::Isolate;
631using v8::Local;
632using v8::Null;
633using v8::Object;
634using v8::String;
635using v8::Value;
636
637void RunCallback(const FunctionCallbackInfo<Value>& args) {
638  Isolate* isolate = args.GetIsolate();
639  Local<Context> context = isolate->GetCurrentContext();
640  Local<Function> cb = Local<Function>::Cast(args[0]);
641  const unsigned argc = 1;
642  Local<Value> argv[argc] = {
643      String::NewFromUtf8(isolate,
644                          "hello world").ToLocalChecked() };
645  cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();
646}
647
648void Init(Local<Object> exports, Local<Object> module) {
649  NODE_SET_METHOD(module, "exports", RunCallback);
650}
651
652NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
653
654}  // namespace demo
655```
656
657This example uses a two-argument form of `Init()` that receives the full
658`module` object as the second argument. This allows the addon to completely
659overwrite `exports` with a single function instead of adding the function as a
660property of `exports`.
661
662To test it, run the following JavaScript:
663
664```js
665// test.js
666const addon = require('./build/Release/addon');
667
668addon((msg) => {
669  console.log(msg);
670// Prints: 'hello world'
671});
672```
673
674In this example, the callback function is invoked synchronously.
675
676### Object factory
677
678Addons can create and return new objects from within a C++ function as
679illustrated in the following example. An object is created and returned with a
680property `msg` that echoes the string passed to `createObject()`:
681
682```cpp
683// addon.cc
684#include <node.h>
685
686namespace demo {
687
688using v8::Context;
689using v8::FunctionCallbackInfo;
690using v8::Isolate;
691using v8::Local;
692using v8::Object;
693using v8::String;
694using v8::Value;
695
696void CreateObject(const FunctionCallbackInfo<Value>& args) {
697  Isolate* isolate = args.GetIsolate();
698  Local<Context> context = isolate->GetCurrentContext();
699
700  Local<Object> obj = Object::New(isolate);
701  obj->Set(context,
702           String::NewFromUtf8(isolate,
703                               "msg").ToLocalChecked(),
704                               args[0]->ToString(context).ToLocalChecked())
705           .FromJust();
706
707  args.GetReturnValue().Set(obj);
708}
709
710void Init(Local<Object> exports, Local<Object> module) {
711  NODE_SET_METHOD(module, "exports", CreateObject);
712}
713
714NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
715
716}  // namespace demo
717```
718
719To test it in JavaScript:
720
721```js
722// test.js
723const addon = require('./build/Release/addon');
724
725const obj1 = addon('hello');
726const obj2 = addon('world');
727console.log(obj1.msg, obj2.msg);
728// Prints: 'hello world'
729```
730
731### Function factory
732
733Another common scenario is creating JavaScript functions that wrap C++
734functions and returning those back to JavaScript:
735
736```cpp
737// addon.cc
738#include <node.h>
739
740namespace demo {
741
742using v8::Context;
743using v8::Function;
744using v8::FunctionCallbackInfo;
745using v8::FunctionTemplate;
746using v8::Isolate;
747using v8::Local;
748using v8::Object;
749using v8::String;
750using v8::Value;
751
752void MyFunction(const FunctionCallbackInfo<Value>& args) {
753  Isolate* isolate = args.GetIsolate();
754  args.GetReturnValue().Set(String::NewFromUtf8(
755      isolate, "hello world").ToLocalChecked());
756}
757
758void CreateFunction(const FunctionCallbackInfo<Value>& args) {
759  Isolate* isolate = args.GetIsolate();
760
761  Local<Context> context = isolate->GetCurrentContext();
762  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
763  Local<Function> fn = tpl->GetFunction(context).ToLocalChecked();
764
765  // omit this to make it anonymous
766  fn->SetName(String::NewFromUtf8(
767      isolate, "theFunction").ToLocalChecked());
768
769  args.GetReturnValue().Set(fn);
770}
771
772void Init(Local<Object> exports, Local<Object> module) {
773  NODE_SET_METHOD(module, "exports", CreateFunction);
774}
775
776NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
777
778}  // namespace demo
779```
780
781To test:
782
783```js
784// test.js
785const addon = require('./build/Release/addon');
786
787const fn = addon();
788console.log(fn());
789// Prints: 'hello world'
790```
791
792### Wrapping C++ objects
793
794It is also possible to wrap C++ objects/classes in a way that allows new
795instances to be created using the JavaScript `new` operator:
796
797```cpp
798// addon.cc
799#include <node.h>
800#include "myobject.h"
801
802namespace demo {
803
804using v8::Local;
805using v8::Object;
806
807void InitAll(Local<Object> exports) {
808  MyObject::Init(exports);
809}
810
811NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
812
813}  // namespace demo
814```
815
816Then, in `myobject.h`, the wrapper class inherits from `node::ObjectWrap`:
817
818```cpp
819// myobject.h
820#ifndef MYOBJECT_H
821#define MYOBJECT_H
822
823#include <node.h>
824#include <node_object_wrap.h>
825
826namespace demo {
827
828class MyObject : public node::ObjectWrap {
829 public:
830  static void Init(v8::Local<v8::Object> exports);
831
832 private:
833  explicit MyObject(double value = 0);
834  ~MyObject();
835
836  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
837  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
838
839  double value_;
840};
841
842}  // namespace demo
843
844#endif
845```
846
847In `myobject.cc`, implement the various methods that are to be exposed.
848Below, the method `plusOne()` is exposed by adding it to the constructor's
849prototype:
850
851```cpp
852// myobject.cc
853#include "myobject.h"
854
855namespace demo {
856
857using v8::Context;
858using v8::Function;
859using v8::FunctionCallbackInfo;
860using v8::FunctionTemplate;
861using v8::Isolate;
862using v8::Local;
863using v8::Number;
864using v8::Object;
865using v8::ObjectTemplate;
866using v8::String;
867using v8::Value;
868
869MyObject::MyObject(double value) : value_(value) {
870}
871
872MyObject::~MyObject() {
873}
874
875void MyObject::Init(Local<Object> exports) {
876  Isolate* isolate = exports->GetIsolate();
877  Local<Context> context = isolate->GetCurrentContext();
878
879  Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::New(isolate);
880  addon_data_tpl->SetInternalFieldCount(1);  // 1 field for the MyObject::New()
881  Local<Object> addon_data =
882      addon_data_tpl->NewInstance(context).ToLocalChecked();
883
884  // Prepare constructor template
885  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New, addon_data);
886  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
887  tpl->InstanceTemplate()->SetInternalFieldCount(1);
888
889  // Prototype
890  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
891
892  Local<Function> constructor = tpl->GetFunction(context).ToLocalChecked();
893  addon_data->SetInternalField(0, constructor);
894  exports->Set(context, String::NewFromUtf8(
895      isolate, "MyObject").ToLocalChecked(),
896      constructor).FromJust();
897}
898
899void MyObject::New(const FunctionCallbackInfo<Value>& args) {
900  Isolate* isolate = args.GetIsolate();
901  Local<Context> context = isolate->GetCurrentContext();
902
903  if (args.IsConstructCall()) {
904    // Invoked as constructor: `new MyObject(...)`
905    double value = args[0]->IsUndefined() ?
906        0 : args[0]->NumberValue(context).FromMaybe(0);
907    MyObject* obj = new MyObject(value);
908    obj->Wrap(args.This());
909    args.GetReturnValue().Set(args.This());
910  } else {
911    // Invoked as plain function `MyObject(...)`, turn into construct call.
912    const int argc = 1;
913    Local<Value> argv[argc] = { args[0] };
914    Local<Function> cons =
915        args.Data().As<Object>()->GetInternalField(0).As<Function>();
916    Local<Object> result =
917        cons->NewInstance(context, argc, argv).ToLocalChecked();
918    args.GetReturnValue().Set(result);
919  }
920}
921
922void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
923  Isolate* isolate = args.GetIsolate();
924
925  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
926  obj->value_ += 1;
927
928  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
929}
930
931}  // namespace demo
932```
933
934To build this example, the `myobject.cc` file must be added to the
935`binding.gyp`:
936
937```json
938{
939  "targets": [
940    {
941      "target_name": "addon",
942      "sources": [
943        "addon.cc",
944        "myobject.cc"
945      ]
946    }
947  ]
948}
949```
950
951Test it with:
952
953```js
954// test.js
955const addon = require('./build/Release/addon');
956
957const obj = new addon.MyObject(10);
958console.log(obj.plusOne());
959// Prints: 11
960console.log(obj.plusOne());
961// Prints: 12
962console.log(obj.plusOne());
963// Prints: 13
964```
965
966The destructor for a wrapper object will run when the object is
967garbage-collected. For destructor testing, there are command-line flags that
968can be used to make it possible to force garbage collection. These flags are
969provided by the underlying V8 JavaScript engine. They are subject to change
970or removal at any time. They are not documented by Node.js or V8, and they
971should never be used outside of testing.
972
973During shutdown of the process or worker threads destructors are not called
974by the JS engine. Therefore it's the responsibility of the user to track
975these objects and ensure proper destruction to avoid resource leaks.
976
977### Factory of wrapped objects
978
979Alternatively, it is possible to use a factory pattern to avoid explicitly
980creating object instances using the JavaScript `new` operator:
981
982```js
983const obj = addon.createObject();
984// instead of:
985// const obj = new addon.Object();
986```
987
988First, the `createObject()` method is implemented in `addon.cc`:
989
990```cpp
991// addon.cc
992#include <node.h>
993#include "myobject.h"
994
995namespace demo {
996
997using v8::FunctionCallbackInfo;
998using v8::Isolate;
999using v8::Local;
1000using v8::Object;
1001using v8::String;
1002using v8::Value;
1003
1004void CreateObject(const FunctionCallbackInfo<Value>& args) {
1005  MyObject::NewInstance(args);
1006}
1007
1008void InitAll(Local<Object> exports, Local<Object> module) {
1009  MyObject::Init(exports->GetIsolate());
1010
1011  NODE_SET_METHOD(module, "exports", CreateObject);
1012}
1013
1014NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
1015
1016}  // namespace demo
1017```
1018
1019In `myobject.h`, the static method `NewInstance()` is added to handle
1020instantiating the object. This method takes the place of using `new` in
1021JavaScript:
1022
1023```cpp
1024// myobject.h
1025#ifndef MYOBJECT_H
1026#define MYOBJECT_H
1027
1028#include <node.h>
1029#include <node_object_wrap.h>
1030
1031namespace demo {
1032
1033class MyObject : public node::ObjectWrap {
1034 public:
1035  static void Init(v8::Isolate* isolate);
1036  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
1037
1038 private:
1039  explicit MyObject(double value = 0);
1040  ~MyObject();
1041
1042  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1043  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
1044  static v8::Global<v8::Function> constructor;
1045  double value_;
1046};
1047
1048}  // namespace demo
1049
1050#endif
1051```
1052
1053The implementation in `myobject.cc` is similar to the previous example:
1054
1055```cpp
1056// myobject.cc
1057#include <node.h>
1058#include "myobject.h"
1059
1060namespace demo {
1061
1062using node::AddEnvironmentCleanupHook;
1063using v8::Context;
1064using v8::Function;
1065using v8::FunctionCallbackInfo;
1066using v8::FunctionTemplate;
1067using v8::Global;
1068using v8::Isolate;
1069using v8::Local;
1070using v8::Number;
1071using v8::Object;
1072using v8::String;
1073using v8::Value;
1074
1075// Warning! This is not thread-safe, this addon cannot be used for worker
1076// threads.
1077Global<Function> MyObject::constructor;
1078
1079MyObject::MyObject(double value) : value_(value) {
1080}
1081
1082MyObject::~MyObject() {
1083}
1084
1085void MyObject::Init(Isolate* isolate) {
1086  // Prepare constructor template
1087  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
1088  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
1089  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1090
1091  // Prototype
1092  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
1093
1094  Local<Context> context = isolate->GetCurrentContext();
1095  constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1096
1097  AddEnvironmentCleanupHook(isolate, [](void*) {
1098    constructor.Reset();
1099  }, nullptr);
1100}
1101
1102void MyObject::New(const FunctionCallbackInfo<Value>& args) {
1103  Isolate* isolate = args.GetIsolate();
1104  Local<Context> context = isolate->GetCurrentContext();
1105
1106  if (args.IsConstructCall()) {
1107    // Invoked as constructor: `new MyObject(...)`
1108    double value = args[0]->IsUndefined() ?
1109        0 : args[0]->NumberValue(context).FromMaybe(0);
1110    MyObject* obj = new MyObject(value);
1111    obj->Wrap(args.This());
1112    args.GetReturnValue().Set(args.This());
1113  } else {
1114    // Invoked as plain function `MyObject(...)`, turn into construct call.
1115    const int argc = 1;
1116    Local<Value> argv[argc] = { args[0] };
1117    Local<Function> cons = Local<Function>::New(isolate, constructor);
1118    Local<Object> instance =
1119        cons->NewInstance(context, argc, argv).ToLocalChecked();
1120    args.GetReturnValue().Set(instance);
1121  }
1122}
1123
1124void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
1125  Isolate* isolate = args.GetIsolate();
1126
1127  const unsigned argc = 1;
1128  Local<Value> argv[argc] = { args[0] };
1129  Local<Function> cons = Local<Function>::New(isolate, constructor);
1130  Local<Context> context = isolate->GetCurrentContext();
1131  Local<Object> instance =
1132      cons->NewInstance(context, argc, argv).ToLocalChecked();
1133
1134  args.GetReturnValue().Set(instance);
1135}
1136
1137void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
1138  Isolate* isolate = args.GetIsolate();
1139
1140  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
1141  obj->value_ += 1;
1142
1143  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
1144}
1145
1146}  // namespace demo
1147```
1148
1149Once again, to build this example, the `myobject.cc` file must be added to the
1150`binding.gyp`:
1151
1152```json
1153{
1154  "targets": [
1155    {
1156      "target_name": "addon",
1157      "sources": [
1158        "addon.cc",
1159        "myobject.cc"
1160      ]
1161    }
1162  ]
1163}
1164```
1165
1166Test it with:
1167
1168```js
1169// test.js
1170const createObject = require('./build/Release/addon');
1171
1172const obj = createObject(10);
1173console.log(obj.plusOne());
1174// Prints: 11
1175console.log(obj.plusOne());
1176// Prints: 12
1177console.log(obj.plusOne());
1178// Prints: 13
1179
1180const obj2 = createObject(20);
1181console.log(obj2.plusOne());
1182// Prints: 21
1183console.log(obj2.plusOne());
1184// Prints: 22
1185console.log(obj2.plusOne());
1186// Prints: 23
1187```
1188
1189### Passing wrapped objects around
1190
1191In addition to wrapping and returning C++ objects, it is possible to pass
1192wrapped objects around by unwrapping them with the Node.js helper function
1193`node::ObjectWrap::Unwrap`. The following examples shows a function `add()`
1194that can take two `MyObject` objects as input arguments:
1195
1196```cpp
1197// addon.cc
1198#include <node.h>
1199#include <node_object_wrap.h>
1200#include "myobject.h"
1201
1202namespace demo {
1203
1204using v8::Context;
1205using v8::FunctionCallbackInfo;
1206using v8::Isolate;
1207using v8::Local;
1208using v8::Number;
1209using v8::Object;
1210using v8::String;
1211using v8::Value;
1212
1213void CreateObject(const FunctionCallbackInfo<Value>& args) {
1214  MyObject::NewInstance(args);
1215}
1216
1217void Add(const FunctionCallbackInfo<Value>& args) {
1218  Isolate* isolate = args.GetIsolate();
1219  Local<Context> context = isolate->GetCurrentContext();
1220
1221  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
1222      args[0]->ToObject(context).ToLocalChecked());
1223  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
1224      args[1]->ToObject(context).ToLocalChecked());
1225
1226  double sum = obj1->value() + obj2->value();
1227  args.GetReturnValue().Set(Number::New(isolate, sum));
1228}
1229
1230void InitAll(Local<Object> exports) {
1231  MyObject::Init(exports->GetIsolate());
1232
1233  NODE_SET_METHOD(exports, "createObject", CreateObject);
1234  NODE_SET_METHOD(exports, "add", Add);
1235}
1236
1237NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
1238
1239}  // namespace demo
1240```
1241
1242In `myobject.h`, a new public method is added to allow access to private values
1243after unwrapping the object.
1244
1245```cpp
1246// myobject.h
1247#ifndef MYOBJECT_H
1248#define MYOBJECT_H
1249
1250#include <node.h>
1251#include <node_object_wrap.h>
1252
1253namespace demo {
1254
1255class MyObject : public node::ObjectWrap {
1256 public:
1257  static void Init(v8::Isolate* isolate);
1258  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
1259  inline double value() const { return value_; }
1260
1261 private:
1262  explicit MyObject(double value = 0);
1263  ~MyObject();
1264
1265  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1266  static v8::Global<v8::Function> constructor;
1267  double value_;
1268};
1269
1270}  // namespace demo
1271
1272#endif
1273```
1274
1275The implementation of `myobject.cc` is similar to before:
1276
1277```cpp
1278// myobject.cc
1279#include <node.h>
1280#include "myobject.h"
1281
1282namespace demo {
1283
1284using node::AddEnvironmentCleanupHook;
1285using v8::Context;
1286using v8::Function;
1287using v8::FunctionCallbackInfo;
1288using v8::FunctionTemplate;
1289using v8::Global;
1290using v8::Isolate;
1291using v8::Local;
1292using v8::Object;
1293using v8::String;
1294using v8::Value;
1295
1296// Warning! This is not thread-safe, this addon cannot be used for worker
1297// threads.
1298Global<Function> MyObject::constructor;
1299
1300MyObject::MyObject(double value) : value_(value) {
1301}
1302
1303MyObject::~MyObject() {
1304}
1305
1306void MyObject::Init(Isolate* isolate) {
1307  // Prepare constructor template
1308  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
1309  tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject").ToLocalChecked());
1310  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1311
1312  Local<Context> context = isolate->GetCurrentContext();
1313  constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1314
1315  AddEnvironmentCleanupHook(isolate, [](void*) {
1316    constructor.Reset();
1317  }, nullptr);
1318}
1319
1320void MyObject::New(const FunctionCallbackInfo<Value>& args) {
1321  Isolate* isolate = args.GetIsolate();
1322  Local<Context> context = isolate->GetCurrentContext();
1323
1324  if (args.IsConstructCall()) {
1325    // Invoked as constructor: `new MyObject(...)`
1326    double value = args[0]->IsUndefined() ?
1327        0 : args[0]->NumberValue(context).FromMaybe(0);
1328    MyObject* obj = new MyObject(value);
1329    obj->Wrap(args.This());
1330    args.GetReturnValue().Set(args.This());
1331  } else {
1332    // Invoked as plain function `MyObject(...)`, turn into construct call.
1333    const int argc = 1;
1334    Local<Value> argv[argc] = { args[0] };
1335    Local<Function> cons = Local<Function>::New(isolate, constructor);
1336    Local<Object> instance =
1337        cons->NewInstance(context, argc, argv).ToLocalChecked();
1338    args.GetReturnValue().Set(instance);
1339  }
1340}
1341
1342void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
1343  Isolate* isolate = args.GetIsolate();
1344
1345  const unsigned argc = 1;
1346  Local<Value> argv[argc] = { args[0] };
1347  Local<Function> cons = Local<Function>::New(isolate, constructor);
1348  Local<Context> context = isolate->GetCurrentContext();
1349  Local<Object> instance =
1350      cons->NewInstance(context, argc, argv).ToLocalChecked();
1351
1352  args.GetReturnValue().Set(instance);
1353}
1354
1355}  // namespace demo
1356```
1357
1358Test it with:
1359
1360```js
1361// test.js
1362const addon = require('./build/Release/addon');
1363
1364const obj1 = addon.createObject(10);
1365const obj2 = addon.createObject(20);
1366const result = addon.add(obj1, obj2);
1367
1368console.log(result);
1369// Prints: 30
1370```
1371
1372[Electron]: https://electronjs.org/
1373[Embedder's Guide]: https://v8.dev/docs/embed
1374[Linking to libraries included with Node.js]: #linking-to-libraries-included-with-nodejs
1375[Native Abstractions for Node.js]: https://github.com/nodejs/nan
1376[V8]: https://v8.dev/
1377[`Worker`]: worker_threads.md#class-worker
1378[bindings]: https://github.com/TooTallNate/node-bindings
1379[download]: https://github.com/nodejs/node-addon-examples
1380[examples]: https://github.com/nodejs/nan/tree/HEAD/examples/
1381[implementation considerations]: n-api.md#implications-of-abi-stability
1382[installation instructions]: https://github.com/nodejs/node-gyp#installation
1383[libuv]: https://github.com/libuv/libuv
1384[node-gyp]: https://github.com/nodejs/node-gyp
1385[require]: modules.md#requireid
1386[v8-docs]: https://v8docs.nodesource.com/
1387