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