That's all there is to my question, really, but I think it's an interesting thing to have answered.
Could one write a native Node.js extension in Go, as opposed to C++?
8.5k Views Asked by user3025492 AtThere are 3 best solutions below

Just to repost this as an answer instead of a comment...
I followed up with golang-nuts mailing list regarding the support for writing extensions in Go for other languages. The source of the response can be found here.
It might be doable for simple things like add (that don't generate garbage or require the runtime), but it's not supported (yet) by either compiler as far as I know. Part of the work is done for linux (see golang.org/issue/256), but there are a number of open questions (what happens when you load two shared objects? etc)
So really, there doesn't seem to be much point in writing an extension in Go, yet, as most of the language features would not be available, and you are already in C/C++ land anyways to add the wrapper for the entry point.

With the addition of support for shared libraries in go, this is possible now.
calculator.go
:
// package name: calculator
package main
import "C"
//export Sum
func Sum(x, y float64) float64 {
return x + y
}
func main() {
}
node-calculator.cc
:
#include "calculator.h"
#include <node.h>
namespace calc {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Number;
using v8::Exception;
void add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
// Check the number of arguments passed.
if (args.Length() < 2) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Wrong number of arguments")));
return;
}
// Check the argument types
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Wrong arguments")));
return;
}
// Perform the operation
Local<Number> num = Number::New(isolate, Sum(args[0]->NumberValue(), args[1]->NumberValue()));
// Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
args.GetReturnValue().Set(num);
}
void init(Local<Object> exports) {
NODE_SET_METHOD(exports, "add", add);
}
NODE_MODULE(calculator, init)
}
binding.gyp
:
{
"targets": [
{
"target_name": "node-calculator",
"sources": [
"node-calculator.cc"
],
"libraries": [
"../calculator.a"
],
},
],
}
test.js
:
const calculator = require('./build/Release/node-calculator');
console.log('4+5=', calculator.add(4, 5));
Build:
go build -buildmode c-archive -o calculator.a calculator.go
node-gyp configure
node-gyp build
Output:
#> node test.js
4+5= 9
Native module for node.js must deeply interact with V8 process which contains a lot of v8 concepts such as gc, javascript context, ...
And I don't think V8 has exposed compatible and stable APIs for other language to interact with it. That is why node.js native addon should be built with C++ and always imports V8 C++ headers.
But you can use GO to write node.js native addons by wrapping GO code with C++:
file: module.go
file: module.c
More about "how to call GO functionn from C/C++":
Call Go functions from C
Edit:
Please see @jdi comments and the link: https://groups.google.com/forum/#!msg/golang-nuts/FzPbOwbTlPs/dAJVWQHx6m4J
Quote: It might be doable for simple things like add (that don't generate garbage or require the runtime), but it's not supported (yet) by either compiler as far as I know. Part of the work is done for linux (see golang.org/issue/256), but there are a number of open questions (what happens when you load two shared objects? etc)