Learn more about Russian war crimes in Ukraine.

Node.js addon hello world

We’re going to make a native extension called addon. Here’s main.js, which uses this extension:

// main.js
const addon = require('./addon');
console.log(addon.hello());

And here it is in action:

$ node main.js
world

Now, you could implement addon in JavaScript, like this:

// addon.js
module.exports.hello = () => 'world';

But instead, we’re going to implement addon in C++ as a Node.js addon! Instead of a file called addon.js, we’ll be making addon.node. The extension .node tells Node.js that it’s a native module, not a JavaScript module.

These .node files can be built with a tool called node-gyp:

$ npm install --save-dev node-gyp  # install for this project

To use it, first create the following binding.gyp file:

# binding.gyp
{
  "targets": [
    {
      "target_name": "addon",
      "sources": [ "addon_src.cc" ]
    }
  ]
}

Then run npx node-gyp configure, which uses the above binding.gyp file. Our binding.gyp says we’re going to build addon.node from the source file addon_src.cc. Make that next:

// addon_src.cc
#include <node.h>

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Value;

void Method(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  v8::MaybeLocal<v8::String> str = String::NewFromUtf8(isolate, "world", NewStringType::kNormal);
  v8::Local<v8::String> checkedString = str.ToLocalChecked();
  v8::ReturnValue<v8::Value> retVal = args.GetReturnValue();
  retVal.Set(checkedString);
}

void Initialize(Local<Object> exports) {
  NODE_SET_METHOD(exports, "hello", Method);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

With everything in place, we can build our addon.node file with npx node-gyp build:

$ npx node-gyp build

If you get build errors here, it’s likely because the V8 API has changed. The above example works for Node 12.x. Consult the addons docs for a latest working example. Due to V8 API instability, Node.js provides “Native Abstractions for Node.js”, a bunch of macros which are hopefully more stable. I’ll do a future post on a NAN hello world.

If you don’t get build errors, you should now have a file at build/Release/addon.node. Copy it to the local directory, and run our main script:

$ npx node-gyp build
$ cp build/Release/addon.node .
$ node main.js  # uses addon.node!
world

(Copying the addon.node file to the local directory is a bit ugly. A popular alternative is the bindings npm package, which has logic to require from all common locations that node-gyp outputs to.)

What can computers do? What are the limits of mathematics? And just how busy can a busy beaver be? This year, I’m writing Busy Beavers, a unique interactive book on computability theory. You and I will take a practical and modern approach to answering these questions — or at least learning why some questions are unanswerable!

It’s only $19, and you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

After months of secret toil, I and Andrew Carr released Everyday Data Science, a unique interactive online course! You’ll make the perfect glass of lemonade using Thompson sampling. You’ll lose weight with differential equations. And you might just qualify for the Olympics with a bit of statistics!

It’s $29, but you can get 50% off if you find the discount code ... Not quite. Hackers use the console!

More by Jim

Tagged #programming. All content copyright James Fisher 2019. This post is not associated with my employer. Found an error? Edit this page.