44
55<!-- type=misc -->
66
7- _ Addons_ are dynamically-linked shared objects written in C++. The
8- [ ` require() ` ] [ require ] function can load addons as ordinary Node.js modules.
9- Addons provide an interface between JavaScript and C/C++ libraries .
7+ _ Addons_ are dynamically-linked shared objects that can be loaded via the
8+ [ ` require() ` ] [ ] function as ordinary Node.js modules.
9+ Addons provide a foreign function interface between JavaScript and native code .
1010
1111There are three options for implementing addons:
1212
13- * Node-API
13+ * [ Node-API] [ ] (recommended)
1414* ` nan ` ([ Native Abstractions for Node.js] [ ] )
1515* direct use of internal V8, libuv, and Node.js libraries
1616
17- Unless there is a need for direct access to functionality which is not\
18- exposed by Node-API, use Node-API.
19- Refer to [ C/C++ addons with Node-API] ( n-api.md ) for more information on
20- Node-API.
21-
22- When not using Node-API, implementing addons becomes more complex, requiring\
17+ This rest of this document focuses on the latter, requiring
2318knowledge of multiple components and APIs:
2419
2520* [ V8] [ ] : the C++ library Node.js uses to provide the
@@ -28,7 +23,7 @@ knowledge of multiple components and APIs:
2823 ` v8.h ` header file (` deps/v8/include/v8.h ` in the Node.js source
2924 tree), and is also available [ online] [ v8-docs ] .
3025
31- * [ libuv] [ ] : The C library that implements the Node.js event loop, its worker
26+ * [ ` libuv ` ] [ ] : The C library that implements the Node.js event loop, its worker
3227 threads and all of the asynchronous behaviors of the platform. It also
3328 serves as a cross-platform abstraction library, giving easy, POSIX-like
3429 access across all major operating systems to many common system tasks, such
@@ -87,37 +82,40 @@ void Initialize(Local<Object> exports) {
8782 NODE_SET_METHOD(exports, "hello", Method);
8883}
8984
90- NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
85+ NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) // N.B.: no semi-colon, this is not a function
9186
9287} // namespace demo
9388```
9489
95- All Node.js addons must export an initialization function following
96- the pattern:
90+ On most platforms, the following `Makefile` can get us started:
9791
98- ```cpp
99- void Initialize(Local<Object> exports);
100- NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
92+ <!--lint disable no-tabs remark-lint-->
93+
94+ ```bash
95+ NODEJS_DEV_ROOT ?= $(shell dirname "$$(command -v node)")/..
96+ CXXFLAGS = -std=c++23 -I$(NODEJS_DEV_ROOT)/include/node -fPIC -shared -Wl,-undefined,dynamic_lookup
97+
98+ hello.node: hello.cc
99+ $(CXX) $(CXXFLAGS) -o $@ $<
101100```
102101
103- There is no semi-colon after ` NODE_MODULE ` as it's not a function (see
104- ` node.h ` ).
102+ <!-- lint enable no-tabs remark-lint-->
105103
106- The ` module_name ` must match the filename of the final binary (excluding
107- the ` .node ` suffix).
104+ Then running the following commands will compile and run the code:
108105
109- In the ` hello.cc ` example, then, the initialization function is ` Initialize `
110- and the addon module name is ` addon ` .
106+ ``` console
107+ $ make
108+ $ node -p ' require("./hello.node").hello()'
109+ world
110+ ```
111+
112+ To integrate with the npm ecosystem, see the [ Building] [ ] section.
111113
112- When building addons with ` node-gyp ` , using the macro ` NODE_GYP_MODULE_NAME ` as
113- the first parameter of ` NODE_MODULE() ` will ensure that the name of the final
114- binary will be passed to ` NODE_MODULE() ` .
114+ ### Context-aware addons
115115
116116Addons defined with ` NODE_MODULE() ` can not be loaded in multiple contexts or
117117multiple threads at the same time.
118118
119- ### Context-aware addons
120-
121119There are environments in which Node.js addons may need to be loaded multiple
122120times in multiple contexts. For example, the [ Electron] [ ] runtime runs multiple
123121instances of Node.js in a single process. Each instance will have its own
@@ -257,8 +255,8 @@ changes:
257255In order to be loaded from multiple Node.js environments,
258256such as a main thread and a Worker thread, an add-on needs to either:
259257
260- * Be an Node-API addon, or
261- * Be declared as context-aware using `NODE_MODULE_INIT()` as described above
258+ * Be an [ Node-API][] addon.
259+ * Be declared as context-aware using `NODE_MODULE_INIT()` as described above.
262260
263261In order to support [`Worker`][] threads, addons need to clean up any resources
264262they may have allocated when such a thread exits. This can be achieved through
@@ -340,7 +338,7 @@ require('./build/Release/addon');
340338Once the source code has been written, it must be compiled into the binary
341339` addon.node ` file. To do so, create a file called ` binding.gyp ` in the
342340top-level of the project describing the build configuration of the module
343- using a JSON-like format. This file is used by [ node-gyp] [ ] , a tool written
341+ using a JSON-like format. This file is used by [ ` node-gyp ` ] [ ] , a tool written
344342specifically to compile Node.js addons.
345343
346344``` json
@@ -375,7 +373,7 @@ version of `node-gyp` to perform this same set of actions, generating a
375373compiled version of the addon for the user's platform on demand.
376374
377375Once built, the binary addon can be used from within Node.js by pointing
378- [ ` require() ` ] [ require ] to the built ` addon.node ` module:
376+ [ ` require() ` ] [ ] to the built ` addon.node ` module:
379377
380378``` js
381379// hello.js
@@ -422,18 +420,46 @@ aware of:
422420### Loading addons using ` require() `
423421
424422The filename extension of the compiled addon binary is ` .node ` (as opposed
425- to ` .dll ` or ` .so ` ). The [ ` require() ` ] [ require ] function is written to look for
423+ to ` .dll ` or ` .so ` ). The [ ` require() ` ] [ ] function is written to look for
426424files with the ` .node ` file extension and initialize those as dynamically-linked
427425libraries.
428426
429- When calling [ ` require() ` ] [ require ] , the ` .node ` extension can usually be
427+ When calling [ ` require() ` ] [ ] , the ` .node ` extension can usually be
430428omitted and Node.js will still find and initialize the addon. One caveat,
431429however, is that Node.js will first attempt to locate and load modules or
432430JavaScript files that happen to share the same base name. For instance, if
433431there is a file ` addon.js ` in the same directory as the binary ` addon.node ` ,
434- then [ ` require('addon') ` ] [ require ] will give precedence to the ` addon.js ` file
432+ then [ ` require('addon') ` ] [ ` require()` ] will give precedence to the ` addon.js ` file
435433and load it instead.
436434
435+ ### Loading addons using ` import `
436+
437+ <!-- YAML
438+ added:
439+ - v23.6.0
440+ - v22.20.0
441+ -->
442+
443+ > Stability: 1.0 - Early development
444+
445+ You can use the [ ` --experimental-addon-modules ` ] [ ] flag to enable support for
446+ both static ` import ` and dynamic ` import() ` to load binary addons.
447+
448+ If we reuse the Hello World example from earlier, you could do:
449+
450+ ``` mjs
451+ // hello.mjs
452+ import myAddon from ' ./hello.node' ;
453+ // N.B.: import {hello} from './hello.node' would not work
454+
455+ console .log (myAddon .hello ());
456+ ```
457+
458+ ``` console
459+ $ node --experimental-addon-modules hello.mjs
460+ world
461+ ```
462+
437463## Native abstractions for Node.js
438464
439465Each of the examples illustrated in this document directly use the
@@ -453,59 +479,7 @@ illustration of how it can be used.
453479
454480> Stability: 2 - Stable
455481
456- Node-API is an API for building native addons. It is independent from
457- the underlying JavaScript runtime (e.g. V8) and is maintained as part of
458- Node.js itself. This API will be Application Binary Interface (ABI) stable
459- across versions of Node.js. It is intended to insulate addons from
460- changes in the underlying JavaScript engine and allow modules
461- compiled for one version to run on later versions of Node.js without
462- recompilation. Addons are built/packaged with the same approach/tools
463- outlined in this document (node-gyp, etc.). The only difference is the
464- set of APIs that are used by the native code. Instead of using the V8
465- or [ Native Abstractions for Node.js] [ ] APIs, the functions available
466- in the Node-API are used.
467-
468- Creating and maintaining an addon that benefits from the ABI stability
469- provided by Node-API carries with it certain
470- [ implementation considerations] [ ] .
471-
472- To use Node-API in the above "Hello world" example, replace the content of
473- ` hello.cc ` with the following. All other instructions remain the same.
474-
475- ``` cpp
476- // hello.cc using Node-API
477- #include < node_api.h>
478-
479- namespace demo {
480-
481- napi_value Method(napi_env env, napi_callback_info args) {
482- napi_value greeting;
483- napi_status status;
484-
485- status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
486- if (status != napi_ok) return nullptr;
487- return greeting;
488- }
489-
490- napi_value init(napi_env env, napi_value exports) {
491- napi_status status;
492- napi_value fn;
493-
494- status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
495- if (status != napi_ok) return nullptr;
496-
497- status = napi_set_named_property(env, exports, "hello", fn);
498- if (status != napi_ok) return nullptr;
499- return exports;
500- }
501-
502- NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
503-
504- } // namespace demo
505- ```
506-
507- The functions available and how to use them are documented in
508- [C/C++ addons with Node-API](n-api.md).
482+ See [ C/C++ addons with Node-API] [ Node-API ] .
509483
510484## Addon examples
511485
@@ -1378,18 +1352,20 @@ console.log(result);
13781352// Prints: 30
13791353```
13801354
1355+ [ Building]: #building
13811356[Electron]: https:// electronjs.org/
13821357[Embedder' s Guide]: https://v8.dev/docs/embed
13831358[Linking to libraries included with Node.js]: #linking-to-libraries-included-with-nodejs
13841359[Native Abstractions for Node.js]: https://github.com/nodejs/nan
1360+ [Node-API]: n-api.md
13851361[V8]: https://v8.dev/
1362+ [`--experimental-addon-modules`]: cli.md#--experimental-addon-modules
13861363[`Worker`]: worker_threads.md#class-worker
1364+ [`libuv`]: https://github.com/libuv/libuv
1365+ [`node-gyp`]: https://github.com/nodejs/node-gyp
1366+ [`require()`]: modules.md#requireid
13871367[bindings]: https://github.com/TooTallNate/node-bindings
13881368[download]: https://github.com/nodejs/node-addon-examples
13891369[examples]: https://github.com/nodejs/nan/tree/HEAD/examples/
1390- [implementation considerations]: n-api.md#implications-of-abi-stability
13911370[installation instructions]: https://github.com/nodejs/node-gyp#installation
1392- [libuv]: https://github.com/libuv/libuv
1393- [node-gyp]: https://github.com/nodejs/node-gyp
1394- [require]: modules.md#requireid
13951371[v8-docs]: https://v8docs.nodesource.com/
0 commit comments