node-addon-api #1 Hello World

408 阅读2分钟

在 electron 的开发中,即使 node 赋予了我们很多能操作操作系统的 API,但是对于过于底层的操作,我们仍然需要使用「系统层面」的语言类似于「cpp」「c」「zig」「rust」等,node-addon-api 带给了我们这样的可能,使我们能够在 javascript 中调用 cpp 。napi-rs 也让我们能调用 rust,本文主要讲述 node-addon-api。

cpp-js Hello World

让我们从 Hello World 开始吧。

/*
  * napi.h 提供了一系列的 C++ 接口,用于创建和使用 Node.js 附加模块。
 */
#include <napi.h>
 
 
/*
  * 定义了一个 Method 方法,返回一个字符串 "world"。
*/
Napi::String Method(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  return Napi::String::New(env, "Hello World!");
}
 
/*
  * 定义了一个 Init 方法,用于初始化 Node.js 附加模块。
  * 该方法接收两个参数:
   * 第一个参数是环境变量,用于获取 Node.js 运行时环境信息。
   * 第二个参数是 exports 对象,用于导出方法和属性。
  * 声明了一个 hello 方法,并指向了 Method
*/
Napi::Object Init(Napi::Env env, Napi::Object exports) {
  exports.Set(Napi::String::New(env, "hello"),
              Napi::Function::New(env, Method));
  return exports;
}
 
 
/*
  * 导出 init 方法作为模块初始化函数。
*/ 
NODE_API_MODULE(hello, Init)

好的,现在我们已经创建了一个 node-model , 但是该如何让 js 感知到这个模块到存在呢?

使用「bindings」

「bindings」导出了一个方法,bind(name: string) 能够查询我们导出的模块 xxx.node

不过在此之前,我们需要将我们书写的 cpp 打包成为 xxx.node

在同级目录下创建「binding.gyp」 并按照类似于以下的配置

{
  "targets": [
    {
      "target_name": "hello",
      "cflags!": [ "-fno-exceptions" ],
      "cflags_cc!": [ "-fno-exceptions" ],
      "sources": [ "hello.cc" ],
      "include_dirs": [
        "<!@(node -p "require('node-addon-api').include")"
      ],
      'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
    }
  ]
}

target_name 将决定我们打包结果的 xxx.node 的 name

sources 代表我们需要将哪个 cpp 模块导出

include_dirs 代表向 cpp 暴露哪些 lib

好的现在我们已经可以使用这一个 model 了

import addon from 'bindings'
 
console.log(addon('hello').hello()); // 'Hello World!'