On this page

🌐 Migrating to Node-API

本教程的目的是让你清楚了解将现有的 NAN Node 本地插件模块迁移到使用 node-addon-apiNode-API 所需的步骤和可用工具。

🌐 The objective of this tutorial is to give you a good idea of the steps necessary and the tools available to migrate an existing NAN Node native add-on module to Node-API using the node-addon-api package.

本教程使用 Node-API 提供的转换工具,帮助你在迁移上取得初步进展。然而,转换工具的作用有限。仍需按照下文所述进行进一步的手动清理。

🌐 This tutorial uses the conversion tool supplied with Node-API to give you a head start on the migration. However, the conversion tool will only get you so far. Further manual cleanup is still required as described below.

为了保持一定的约束,本教程使用 node-microtime,这是一个基于 NAN 的简单本地插件。该插件通过系统调用来确定当前时间的微秒级分辨率(如果操作系统支持的话)。

🌐 To keep things somewhat constrained, this tutorial uses node-microtime which is a simple NAN-based native add-on. This add-on makes system calls to determine the current time to microsecond resolution if supported by the operating system.

在开始之前,请确保你已经安装了所有必要的前置条件工具

🌐 Before you start, make sure you've got all the necessary prerequisites and tools installed.

Node-API 在所有当前支持的 Node.js 版本中都是稳定的。请使用 Active LTS 或 Maintenance LTS 版本。你可以使用 node -v 检查你正在运行的 Node.js 版本。

🌐 Clone node-microtime

第一步,将 node-microtime GitHub 仓库克隆到你的系统上:

🌐 As a first step, clone the node-microtime GitHub repository to your system:

在我们进行修改之前,最好先构建并测试 node-microtime,以帮助验证必要的开发工具是否已正确安装和配置。

🌐 Before we make our modifications, it's a good idea to first build and test node-microtime to help verify that the necessary development tools have been correctly installed and configured.

由于 node-microtime 已经迁移到 node-addon-api,你必须切换到标签 v2.1.9 才能按照教程进行。

cd node-microtime
git checkout tags/v2.1.9
npm install
npm test

npm install 命令调用构建过程,npm test 运行代码。你可能会看到不会影响代码运行能力的编译器警告。当成功构建并运行时,你应该会看到类似如下的输出:

🌐 The npm install command invokes the build process and npm test runs the code. You may see compiler warnings that do not affect the ability to run the code. When successfully built and run, you should see output that looks something like this:

microtime.now() = 1526334357974754
microtime.nowDouble() = 1526334357.976626
microtime.nowStruct() = [ 1526334357, 976748 ]

Guessing clock resolution...
Clock resolution observed: 1us

🌐 Run the conversion tool

一旦代码的基本操作已经得到验证,下一步是运行 Node-API 转换工具。请注意,转换工具会_直接替换文件_。切勿在项目的唯一副本上运行转换工具。显然,你也只想运行它_一次_。

🌐 Once the basic operation of the code has been verified, the next step is to run the Node-API Conversion Tool. Be aware that the conversion tool replaces files in place. Never run the conversion tool on the only copy of your project. And obviously, you want to run it only once.

npm install --save node-addon-api
node ./node_modules/node-addon-api/tools/conversion.js ./

对于这个小项目,转换工具运行非常快。目前,转换工具已修改了以下项目文件:

🌐 For this small project, the conversion tool runs very quickly. At this point, the conversion tool has modified the following project files:

  • binding.gyp
  • package.json
  • src/microtime.cc

继续重建转换后的代码:

🌐 Go ahead and rebuild the converted code:

正如你所看到的,有一个或多个需要解决的编译错误。有时可能会很多,但没有什么是无法克服的。

🌐 As you'll see, there are one or more compile errors that need to be addressed. There can be quite a few at times, but nothing insurmountable.

🌐 Cleanup

转换工具无法预测每一种编码情况。因此,通常会有需要手动处理的问题。以下是你在此项目中可能遇到的问题。最佳方法是一次处理一个问题,在处理每个问题后尝试 npm install,直到不再出现错误。

🌐 The conversion tool cannot anticipate every coding situation. So there will typically be issues that need to be addressed manually. Below are the issues you're likely to encounter with this project. The best approach is to address each issue, one at a time, and attempt the npm install after addressing each issue until there are no more errors.

🌐 Cannot find module 'nan'

此错误及其对应的 napi.h 无法找到的情况,是由于 binding.gyp 文件中缺少代码。对于这个项目,你将在 binding.gyp 中看到这段代码:

🌐 This error, and its counterpart where napi.h cannot be found, is due to code missing in the binding.gyp file. For this project, you'll see this code in the binding.gyp:

C/C++ 包含目录仍然指向 NAN。它们需要改为指向 Node-API。上面的一行应替换为这一行:

🌐 The C/C++ include directories are still pointing to NAN. They need to point to Node-API instead. The line above should be replaced with this line:

在其他项目中,你可能会收到一个错误,提示找不到 napi.h。原因与此相同。每个目标的 include_dirs 属性必须包含对 node-addon-api 的引用,如上所示。

🌐 On other projects you may receive an error where napi.h cannot be found. The cause is the same as this one. The include_dirs property of each target must include the reference to node-addon-api as shown above.

🌐 Use of undeclared identifier 'env'

这三个 C++ 函数——NowNowDoubleNowStruct——都引用了未定义的 env 变量。env 用于保存 Node-API Environment 变量,这对于几乎所有的 Node-API 调用都是必需的。env 的值可以很容易地从传递给每个 C++ 函数的 Napi::CallbackInfo 参数中获得。纠正此错误的一种方法是在每个函数体的第一行添加以下代码:

🌐 The three C++ functions-Now, NowDouble, and NowStruct-each make a reference to the env variable which is not defined. env is meant to hold the Node-API Environment variable which is essential to nearly all Node-API calls. The value for env can be easily obtained from the Napi::CallbackInfo argument passed to each C++ function. One technique to correct this error is to add the following code as the first line in the body of each function:

另一种方法是将三函数中每个 env 的实例替换为 info.Env()。选择权在你手中。

🌐 An alternative would be to replace each instance of env in the three functions with info.Env(). The choice is yours.

🌐 Use of void as the return value

这三个 C++ 函数——NowNowDoubleNowStruct 都被定义为返回 void 类型的值。实际上,它们每个都应该返回一个 JavaScript 值。实现这一点的最好方法是将 void 替换为 Napi::Value。这样每个函数就可以返回一个类型未确定的 JavaScript 值。它可以是任何 JavaScript 值,包括字符串、数字、布尔值、数组等。它们应该如下所示:

🌐 Each of the three C++ functions-Now, NowDouble, and NowStruct are defined to return a void value. In fact, they should each be returning a JavaScript value. The best way to accomplish this is by replacing the void with Napi::Value. This permits each of the functions to return a JavaScript value of undetermined type. It could be any JavaScript value including String, Number, Boolean, Array, etc. Here's what they should look like:

Napi::Value Now(const Napi::CallbackInfo&info) {
Napi::Value NowDouble(const Napi::CallbackInfo&info) {
Napi::Value NowStruct(const Napi::CallbackInfo&info) {

🌐 A new way to define exports

Node-API 使用不同的技术来定义 exports 对象。

🌐 Node-API uses a different technique for defining the exports object.

代码:

🌐 The code:

Nan::Export(target, "now", Now);
Nan::Export(target, "nowDouble", NowDouble);
Nan::Export(target, "nowStruct", NowStruct);

需要被替换为:

🌐 Needs to be replaced with:

exports.Set(Napi::String::New(env,"now"), Napi::Function::New(env, Now));
exports.Set(Napi::String::New(env,"nowDouble"), Napi::Function::New(env, NowDouble));
exports.Set(Napi::String::New(env,"nowStruct"), Napi::Function::New(env, NowStruct));

exports 是一个 Napi::Object,它表示一个 JavaScript 对象。Set 方法设置对象上属性的值,并接受两个参数:属性的名称及其值。这两个参数都必须是 JavaScript 值。

另一项更改对 Node-API 的运行至关重要。InitAll 函数 必须 返回 exports 变量。这一行必须出现在函数体的最后一行:

🌐 One more change is critical to the operation of Node-API. The InitAll function must return the exports variable. This line must appear as the last line in the body of the function:

未添加此行可能会导致运行时出现段错误。

🌐 Failure to add this line will likely result in a segfault error at runtime.

🌐 Replacement for ErrnoException

在 Node-API 中不存在 NAN ErrnoException 对象。现有代码如下所示:

🌐 The NAN ErrnoException object does not exist in Node-API. The existing code looks like:

但它可以很容易地被看起来像这样的代码替代:

🌐 But it can easily be replaced with code that looks like this:

std::string msg =  "gettimeofday: " + std::string(strerror(errno));
Napi::Error::New(env, msg).ThrowAsJavaScriptException();

🌐 Final check

一旦代码编译无误,测试你所做的更改:

🌐 Once the code compiles without error, test the changes you've made:

你应该会看到与迁移前类似的结果。

🌐 You should see results similar to those from before the migration.

恭喜!你刚刚将你的第一个 NAN 模块转换为 Node-API。

🌐 Congratulations! You've just converted your first NAN module to Node-API.

🌐 Conclusion

不可否认,本教程只是初步介绍了将 NAN 模块迁移到 Node-API 的方法。然而,基本方法是相同的。运行转换,尝试编译,解决错误,再次编译。洗。冲。重复。

🌐 Admittedly, this tutorial just scratches the surface on migrating NAN modules to Node-API. However, the basic approach is the same. Run the conversion, attempt a compile, address the errors, compile again. Wash. Rinse. Repeat.