The Blog

 

I recently upgraded a Node.js-addon written in C++ to run on Node.js 12. I started with little understanding of C++ or how to develop Node.js-addons, so I’m sharing what I learned to make the process easier for others faced with similar challenges.

Prior to my upgrade, trying to compile V4 of Node Application Metrics (Appmetrics) on Node.js 12 showed lots of compilation errors. The errors occurred because Node.js 12 runs on a higher version (7.4) of Google’s V8 engine, which has deprecated several functions. Although Google V8 list their deprecations, they do not explain how to upgrade your deprecated code!

In this blog post, I share with you the steps I took to get my code to run error-free and how you can get your own C++ Node.js-addons running on Node.js 12.

Learning by example

I didn’t have a lengthy background working with Appmetrics, C++, or Node.js-addons, so I learned by trying other people’s examples and figuring out what worked and why.

To start with, I updated the syntax of my native C++ code, and got Appmetrics running on Node.js 12. However, now my C++ no longer ran on Node.js 8, since my fixes used syntax that had been introduced after Node.js 8. To get around this, I could have used pre-compiler if-else blocks to run the correct code for Node.js versions 8, 10, and 12 respectively, but that would have been clunky and likely need extending to run on future versions of Node.js.

NAN to the rescue

Then I found Native Abstractions for Node.js (NAN). NAN’s API mostly stays the same across most major versions of Node.js, no matter which version of Google’s V8 engine is running. So, I converted many native C++ types and functions to NAN types and functions, effectively delegating to NAN the job of maintaining compatibility across major versions of Node.js.

There is a more modern alternative to NAN called N-API. N-API also aims to provide a single API that remains consistent across most major version of Node.js. Where NAN insulates you from most but not all of the updates to Google’s V8 API, N-API insulates you from all of them.

I used NAN instead of N-API because NAN was already partially in the codebase. I had to get Appmetrics running on Node 12 quickly, so I implemented the quickest fix first: extending our usage of NAN. But if you’re writing a Node.js-addon from scratch, check out N-API.

Conclusion

After a good deal of Googling, experimenting and talking with colleagues, I got Appmetrics to compile on Node.js versions 8, 10, and 12 by converting some native C++ syntax to NAN types and functions. Much of our code is still in native C++, parts of which will probably be deprecated in future versions of Node.js. To get one step ahead of future deprecations, we should resolve deprecation warnings before they become errors – using NAN or N-API.

Caveat

If you view my code changes in this pull request, you’ll see that I’m using Local types rather than the new MaybeLocal types introduced in version 7.4 of Google’s V8 engine (which Node.js 12 runs on).

Overusing Local types is not a best practice, but it was necessary to use them to get Appmetrics running on Node 12 as quickly as possible. However, returning MaybeLocal types would be safer.

The risk is that C++ calls that might internally call back out to user-provided JavaScript can fail. A MaybeLocal<> is a wrapper around Local<> that enforces a check whether the Local<> is empty before it can be used. This allows us to throw an exception on failure instead of abort()ing.

For more information related to this caveat, see:

Thanks to Howard Hellyer, Matt Colegate, Richard Lau, Michael Dawson, Sam Roberts, and Emily Mitchell.