简介
Node.js 插件是一个 C++ 写的动态链接库。Node.js 中的 require()
可以直接加载插件作为一个 Node.js 模块。插件提供了 Node.js 与 C++ 库之间的接口。
实现插件有三种方式:N-API, nan 和直接用内部的 V8, libuv 以及 Node.js 库。官方推荐使用 N-API 实现插件,除非要用到 N-API 没有暴露出来的接口。
N-API
N-API 是用于构建 native Node.js 插件一系列 C API 。它独立于 JavaScript 运行时(如 V8 ),由 Node.js 团队维护。
N-API 在 Node.js 版本之间是 ABI 稳定的。意味着你只需要编译一次就可以在后续的
Node.js 版本运行。
node-addon-api
node-addon-api 将 N-API 封装成 C++ 接口,开发起来更加方便和快速。
参考文章:
从暴力到 NAN 再到 NAPI——Node.js 原生模块开发方式变迁
node-addon-api
N_API
HelloWorld
下面我们用 node-addon-api 写一个 计算 Fibonacci 插件,实现等同于下面这个 JavaScript
函数。
1
2
3
4
5
6
7
8
9
| function fibonacci(n) {
var a = 0, b = 1
for (var i = 0; i < n; i++) {
var tmp = a
a = b
b = tmp + b
}
return a
}
|
步骤
首先我们新建一个目录叫 Fibonacci ,并添加一个 package.json 文件。
1
2
3
4
5
6
7
8
| {
"name": "fibonacci",
"version": "1.0.0",
"devDependencies": {
"cmake-js": "latest",
"node-addon-api": "latest"
}
}
|
node-addon-api 就是我们开发需要的 API 。
CMake.js 是一个基于 CMake 的构建 Node.js 插件的工具。所以我们需要写一个
CMakeLists.txt 。可以通过 npm 安装一个全局的 CMake.js
1
| npm install -g cmake-js
|
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
| cmake_minimum_required(VERSION 3.7)
project (fibonacci)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
## include
## CMake.js 会收集头文件路径到 CMAKE_JS_INC 中
include_directories(${CMAKE_JS_INC})
add_library(${PROJECT_NAME} SHARED "")
## CMake.js
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_JS_INC})
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_JS_LIB})
## node-addon-api
execute_process(COMMAND node -p "require('node-addon-api').include"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE NODE_ADDON_API_DIR
)
string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR})
target_sources(${PROJECT_NAME} PRIVATE
fibonacci.cpp)
|
在 fibonacci.cpp 中写上我们的插件代码。
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
30
31
32
33
34
35
| #include <napi.h>
unsigned long long Fibonacci(int n) {
unsigned long long a = 0, b = 1;
for (int i = 0; i < n; i++) {
unsigned long long tmp = a;
a = b;
b = tmp + b;
}
return a;
}
Napi::Value ExportFibonacci(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1) {
Napi::TypeError::New(env, "wrong number of arguments").ThrowAsJavaScriptException();
return env.Null();
}
if (!info[0].IsNumber()) {
Napi::TypeError::New(env, "wrong type of arguments").ThrowAsJavaScriptException();
}
auto n = info[0].As<Napi::Number>().Int32Value();
auto result = Fibonacci(n);
Napi::Number num = Napi::Number::New(env, result);
return num;
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "fibonacci"), Napi::Function::New(env, ExportFibonacci));
return exports;
}
NODE_API_MODULE(fibonacci, Init);
|
然后用 CMake.js 编译我们的代码,在 Fibonacci 目录执行下面的命令。
1
2
| cmake-js configure
cmake-js build
|
最后会在 build/Release
目录下生成 fibonacci.node
现在就可以在 JavaScript 中 require
这个插件
1
2
3
| const fibonacci = require("./build/Release/fibonacci.node")
console.log(fibonacci.fibonacci(10))
|