在 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!'