Search code examples
javascriptc++node.jsrequirev8

Node.js C++ add-on trying to execute javascript code with `require` function


I'm maintaining a Node.js add-on in C++.

I need to call a SQL parser (a very non-standard variant of SQL, actually) inside an asynchronously called C++ function, but unfortunately (for me) that parser has been implemented in Javascript using some Node.js libraries (the function require is being used); this is an example of the kind of javascript code I need to execute:

require("./util/SqlParser")("SELECT 1 FROM DUAL").getSyntaxTree()

I've tried writing something like this:

v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::TryCatch trycatch;
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate
    ,
    "require(\"./util/SqlParser\")(\"SELECT 1 FROM DUAL\").getSyntaxTree()"
    ,
    v8::NewStringType::kNormal).ToLocalChecked()
    ;
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::MaybeLocal<v8::Value> result = script->Run(context);
if( result.IsEmpty() )
{
    v8::Local<v8::Value> exc = trycatch.Exception();
    if( !exc.IsEmpty() )
    {
        auto msg = exc->ToString();
        if( !msg.IsEmpty() )
            throw std::string( *v8::String::Utf8Value(msg) );
    }
    throw "unknown error in called js function";
}

But unfortunately this doesn't work. The net outcome is the error message "ReferenceError: require is not defined": apparently, my context doesn't know anything about Node.js.

I tried to wrap the above expression in a js function parseSqlText, but this function is equally unknown to the script executor (I get the error message "ReferenceError: parseSqlText is not defined").

My question is: is there any way to get around this?

Any help would be very appreciated. I would be very glad to avoid reimplementing that parser in C++... which at present seems the only viable way to do what I need.


Solution

    • First, v8 is not Node.js, Node.js is built on top of v8.
    • v8 is a javascript engine
    • Thus Node.js libraries are not carried with v8 by it-self

          The N-API is the answer to question. Although, normally it is used to write native C++ plugins for Node.js. The github thread belwo has some examples. Additionally, the node.js docs for N-API have also been linked.
          Github Thread
          Node N-API Docs

    EDIT: It would seem the work has been done already, here in this repository. The writer made it so it appears to abstract all the prep work of v8 and be one line for you.

    #include "node_embed.h"
    
    int main(int argc, char** argv) {
        node_context *context = nodeSetup(argc, argv);
    
        if (context) {
            nodeExecuteString(context, "let foo = 1", "__init__");
            nodeExecuteString(context, "foo = 2", "__init__");
            nodeExecuteString(context, "console.log(foo)", "__init__");
    
            return nodeTeardown(context);
        } else {
           return 12;
        }
    }
    

    The above is from the repository and will allow you to run that snippet of code.