Ways to Write Node.js Native Addon with C++

August 05, 2022

Background

When building full-stack JavaScript application, the need to let JavaScript to talk to a C or C++ API may arises due to the following reasons:

  • The operating system, database or other native software only provide API to C or C++.
  • The code is CPU-intensive such that using C or C++ to compute will provide a performance boost comparing to implementing in JavaScript.
  • etc...

Thus, we may consider to use C++ to write a native addon for JavaScript.

What is a native addon?

Native addon is essencially a DLL (Dynamically Linked Library) which also called SO (Shared Object) on Linux. It can be loaded in the runtime by a program. Specifically, it can be used as a normal Node module through require() or import as it exposes an API that is capatible with your JavaScript environment. The compiled native addon usually has a .node extension.

Ways to write a native addon

1. Direct Use of Internal V8, libuv and Node.js Libraries

Node.js and its libraries (e.g. V8, libuv, OpenSSL and etc.) provides APIs through their header file. These files are located at /include/node/ folder of your Node.js installation location. You can directly calling these APIs to write the module using C++ as V8, the core of Node.js, is written in C++. However, the module will be tightly dependent to the internal implementation of the Node.js and other libraries. As the implementation of these dependencies may change, it may break the ABI stability. Eventually, whenever the Node.js released a new version, the native module you build with the old version of Node.js headers may not be capatible.

You can learn more about ABI stability on Node.js official documentation .

Examples of using this approach can be found at here .

2. NAN

To solve the ABI stability problem mentioned above, the NAN project ( https://github.com/nodejs/nan ) appears. This project abstracts the internal implementation of Node.js and the V8 engine by adding C++ wrappers and marcos around their APIs. However, NAN project does not completely abstract V8 API and does not provide full support for all the libraries used inside Node.js. Besides, the NAN project was maintained independently from the Node.js project which means whenever a new Node.js version releases, we have to wait NAN to add support for such new version before users can use our native addon. On the good side though, it can support a lot of Node.js versions especially the old ones like 0.8, 0.10, 0.12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 and 18 (as of Aug 2022).

Examples of using this approach can be found at here or here (under nan folder of each example).

3. N-API (Node-API)

To solve the maintainance problem, the N-API apperars as the successor of NAN. It is writen in C and maintained as a part of the Node.js project itself. It provides an abstraction layer that abstracts internal implementation of Node.js and its libraries. The API is defined in the headers node_api.h and node_api_types.h, and provides a forward compatibility guarantee that crosses the Node.js major version boundary.

Besides solving the problem above, N-API is also independent from the underlaying JavaScript runtime (e.g. V8) and allows Node.js to switch to other JavaScript engines like Chakra ( https://github.com/chakra-core/ChakraCore ) which eventually builds Node.js on ChakraCore ( https://github.com/nodejs/node-chakracore ).

However, please note that Node.js introduced N-API in version 8.6.0 and marked it as a stable component of the project as of Node.js 8.12.0, which means it is not possible to use N-API to support Node.js version before 8.6.0.

You can learn more about N-API on an article write by Node.js officials here , or on offical Node.js documentation here and here .

Examples of using this approach can be found at here (under napi folder of each example).

4. node-addon-api

As the C API in N-API is little bit hard to use, the node-addon-api module ( https://github.com/nodejs/node-addon-api ) contains header-only wrappers of the N-API in C++. It provides a C++ object model and exception handling semantics with low overhead according to its README file.

Please also note that, as also mentioned in the README file, node-addon-api module is not part of Node.js, but it preserves the benefits of the Node-API as it consists only of inline code that depends only on the stable API provided by Node-API. As such, modules built against one version of Node.js using node-addon-api should run without having to be rebuilt with newer versions of Node.js.

Examples of using this approach can be found at here (under node-addon-api folder of each example).

Reference