0%

nodejs-插件

本文介绍c++插件,简单来讲c++插件就是在c层直接调用v8,可以内置一些js api,通过学习nodejs c++插件,忽然灵光一闪,v8中有一个拦截器,虽然没有用过,但是通过这个拦截器应该可以做js的代理吧,今天先来总结nodejs c++插件,后续会继续研究js的代理。

如果你发现下面我讲的东西你不好理解,你可以查看这个目录下的另一篇文章(https://yuque.antfin.com/xiaobao.spf/ad2gcp/sm0sxn),仔细研读,然后再回来查看这边文章,你会发现nodejs c++插件竟然如此简单。

流程:js - c++插件 - node - v8

官方示例 demo:https://github.com/nodejs/node/tree/v14.17.5/test/addons

更多示例 demo:http://gitlab.alibaba-inc.com/amap_mini/js-v8-demo

参考:
https://nodejs.org/dist/latest-v14.x/docs/api/addons.html
https://github.com/nodejs/node/blob/master/src/node.h

工具

  • node-gyp

    1
    npm install -g node-gyp
  • node https://nodejs.org/zh-cn/

    代码

    hello.cc

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #include <node.h>  //这里很重要,调用的node中的 node.h头文件

    namespace demo {

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

    void Method(const FunctionCallbackInfo<Value>& args) {
    Isolate* isolate = args.GetIsolate(); //获取isolate,
    args.GetReturnValue().Set(String::NewFromUtf8(
    isolate, "i am xiaobao").ToLocalChecked()); //返回值
    }

    void Initialize(Local<Object> exports) {
    NODE_SET_METHOD(exports, "hello", Method);//导出hello方法,
    }

    NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) //导出初始化

    }

    binding.gyp

    1
    2
    3
    4
    5
    6
    7
    8
    {
    "targets": [
    {
    "target_name": "hello",
    "sources": [ "hello.cc" ]
    }
    ]
    }

    hello.js

    1
    2
    3
    const hello = require('./build/Release/hello');

    console.log(hello.hello());

    编译

    1
    2
    3
    4
    # 生成Makefile
    node-gyp configure
    #生成 hello.node
    node-gyp build

    image.png

    运行

    1
    node hello.js

    image.png

解析

hello.cc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 导出hello方法
void Initialize(Local<Object> exports) {
NODE_SET_METHOD(exports, "hello", Method);//
}
// Initialize函数 为 宏NODE_MODULE_INITIALIZER
// node.h
#define NODE_MODULE_INIT() \
extern "C" NODE_MODULE_EXPORT void \
NODE_MODULE_INITIALIZER(v8::Local<v8::Object> exports, \
v8::Local<v8::Value> module, \
v8::Local<v8::Context> context); \
NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, \
NODE_MODULE_INITIALIZER) \
void NODE_MODULE_INITIALIZER(v8::Local<v8::Object> exports, \
v8::Local<v8::Value> module, \
v8::Local<v8::Context> context)

//导出初始化
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

// node.h NODE_MODULE为宏,NODE_GYP_MODULE_NAME也是宏
// Usage: `NODE_MODULE(NODE_GYP_MODULE_NAME, InitializerFunction)`
// If no NODE_MODULE is declared, Node.js looks for the well-known
// symbol `node_register_module_v${NODE_MODULE_VERSION}`.
#define NODE_MODULE(modname, regfunc) \
NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage)

宏 NODE_MODULE_INITIALIZER扩展为 Node.js 在加载插件时期望找到的函数的名称(Initialize函数)

或者可以使用 宏NODE_MODULE_INIT 初始化导出

1
2
3
4
5
6
7
NODE_MODULE_INIT(/* exports, module, context */) {
Isolate* isolate = context->GetIsolate();

AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
}

更多示例

http://gitlab.alibaba-inc.com/amap_mini/js-v8-demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const hello = require('./build/Release/hello');
//模拟call
hello.call((msg) => {
console.log(msg)
});

//模拟 创建对象
const obj1 = hello.createObject("songpengfei");
console.log(obj1.msg);
//模拟创建方法
const fn = hello.createFunction();
console.log(fn());

// 模拟创建自定义对象
const obj2 = new hello.MyObject(20);
console.log(obj2.plusOne());