Building Modern Native Add-ons for Node.js in 2020

This post was contributed by Chengzhong Wu (@legendecas), Gabriel Schulhof (@gabrielschulhof) Jim Schlight (@jimschlight), Kevin Eady Michael Dawson (@mhdawson1), Nicola Del Gobbo (@NickNaso)

Introduction

N-API provides an ABI-stable API that can be used to develop native add-ons for Node.js, simplifying the task of building and supporting such add-ons across Node.js versions.

Image for post
Image for post
Image for post
Image for post

New features/functions

As people have been using N-API and node-addon-api we’ve been adding the key features that have been needed, including generally improving the add-on experience.

Image for post
Image for post

Multi-Threaded and Asynchronous Programming

As Node.js becomes more prominent in the computing world, the need to interact with native OS-level asynchronous activities has grown. Node.js is a single-threaded implementation of the JavaScript language, where only the main thread may interact with JavaScript values.

  • AsyncProgressWorker: similar to the above, adding the ability to provide progress updates for the asynchronous action.
  • Thread-safe functions: provides a mechanism to call into Node.js at any time from any number of threads.

Context-sensitivity

Another recent Node.js development is the arrival of workers. These are full-fledged Node.js environments running in threads parallel to the Node.js main thread. This means that native add-ons can now be loaded and unloaded multiple times as the main process creates and destroys worker threads.

  • napi_get_instance_data() and napi_set_instance_data() in order to provide a place for safely storing global data associated with a single instance of an add-on.
  • The node-addon-api Addon<T> class, which neatly combines the above tools to create a class whose instances represent instances of an add-on present in the various worker threads created by Node.js. Thus, add-on maintainers can store per-add-on-instance data as variables in an instance of the Addon<T> class and Node.js will create an instance of the Addon<T> class whenever it is needed on a new thread:
Image for post
Image for post

Additional helper methods

As package maintainers used N-API we discovered a few additional APIs that were commonly needed. These included:

  • BigInts
  • Retrieving property names from objects
  • Detaching ArrayBuffers

Building

One of the other main areas where the N-API team worked to fill in gaps and make it easier for maintainers to consume N-API was the build workflow, including additions to CMake.js, node-pre-gyp and prebuild.

Resources for getting started

One resource available to help get started is the node-addon-examples GitHub repository, containing samples of various Node.js native add-ons. The root of the repository contains folders for different functional aspects, from a simple Hello World add-on to a more complex multi-threaded add-on. Each example folder contains up to three subfolders: one for each Node.js add-on implementation (legacy NAN, N-API, and node-addon-api). To get started with the Hello World example using the node-addon-api implementation, simply run:

git clone https://github.com/nodejs/node-addon-examples.gitcd node-addon-examples/1_hello_world/node-addon-api/npm inode .
  • migration guide from NAN
  • differences between build systems (node-gyp, cmake, …)
  • context-sensitivity and thread-safety

Closing out and call to action

Since the earliest days Node.js supported the ability to add features written in native code (C / C++) and to expose them through a JavaScript interface. Over time we recognized that there were challenges in implementing, maintaining, and distributing the resulting addons. N-API was identified as one of the core areas for improvements requested by module owners in order to address those challenges. The whole team and the community began to contribute to the creation of this new API in the core.

  • It allows JavaScript engines other than V8 to implement N-API which, in turn, allows add-on maintainers to target different runtimes (such as Babylon Native or IoT.js, and Electron) with the same code they use for supporting Node.js.
  • Since N-API is a C API it is possible to implement native add-ons using languages other than C / C++ (such as Go or Rust).

Get Involved

We are constantly making progress on N-API and in general on the native add-ons ecosystem, but we always need more help. You could help us and the whole community to continue improving N-API in many ways:

  • Porting a native module that your app depends on to N-API
  • Adding new features to N-API
  • Adding new features from N-API to node-addon-api
  • Fixing or adding test cases for node-addon-api
  • Fixing or adding examples to node-addon-examples

Written by

Node.js is a collaborative open source project dedicated to building and supporting the Node.js platform. https://nodejs.org/en/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store