January 05, 2018
Hi

Just wanted to share how I have managed to interface node.js with D using C++ bridge and NAN. So far I have been using C++ and rust for this but for obvious reasons (that would be a long story to explain) I wanted to go with D. One of the show stoppers was the lack of well established (or I don't know if that exists) library of framework to help with that.

Anyway I have managed to do this using information gathered from various places and I wanted to share if anyone runs into the same issue.

First I created a d lib using dub.

Simple code for the library:

import std.string;

extern (C++) immutable(char)* D_func(const char *s) {
        import std.string;
        return toStringz(fromStringz(s) ~ "-response");
}

Code for the c++ file which is the interface to the node.js


#include <nan.h>

char *D_func(const char *);
extern "C" int rt_init();
extern "C" int rt_term();

// NAN_METHOD is a Nan macro enabling convenient way of creating native node functions.
// It takes a method's name as a param. By C++ convention, I used the Capital cased name.
NAN_METHOD(Hello) {

    // send this to D code
    const char *s = "request";
    // Initialize the D runtime
    rt_init();
    // Create an instance of V8's String type
    auto message = Nan::New(D_func(s)).ToLocalChecked();
    // Shut down D
    rt_term();
    // 'info' is a macro's "implicit" parameter - it's a bridge object between C++ and JavaScript runtimes
    // You would use info to both extract the parameters passed to a function as well as set the return value.
    info.GetReturnValue().Set(message);
}

// Module initialization logic
NAN_MODULE_INIT(Initialize) {
    // Export the `Hello` function (equivalent to `export function Hello (...)` in JS)
    NAN_EXPORT(target, Hello);
}

// Create the module called "addon" and initialize it with `Initialize` function (created with NAN_MODULE_INIT macro)
NODE_MODULE(addon, Initialize);

finally the binding.gyp that links the whole thing together and builds the Node.js extension.

the binding.gyp

{
  "targets": [
    {
      "include_dirs": [
        "<!(node -e \"require('nan')\")"
      ],
      "target_name": "addon",
      "sources": [ "main.cpp" ],
      "libraries": [ "-L/path/to/dlang_library", "-ldlang_library",
                     "-L/path/to/phobos/library", "-lphobos2" ]
    }
  ]
}

and the package.json
```
{
  "name": "call_d_from_nodejs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "compile": "node-gyp rebuild",
    "start": "node main.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "nan": "^2.8.0",
    "node-gyp": "^3.6.2"
  }
}
```

enjoy, any questions let me know. :)