ホームページ > ウェブフロントエンド > jsチュートリアル > Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

青灯夜游
リリース: 2022-08-29 20:04:57
転載
2336 人が閲覧しました

Node 拡張機能の開発を実行するにはどうすればよいですか?次の記事では、Node.js 拡張機能を開発するための前提知識を紹介し、Node.js 拡張機能の開発を開始する方法を説明します。

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

Node.js 拡張機能を開発する理由

1.Node.js は CPU には適していません。集中的なアプリケーション ビジネス、非同期計算用の libuv スレッド プールを使用した拡張機能の開発

2. JavaScript よりも効率的な C、Rust、その他の言語の使用など、より高い実行パフォーマンスが必要です

3既存の C ライブラリ。開発の繰り返しを避けるため、JavaScript 呼び出し用の Node.js 拡張機能に直接カプセル化されます。

4. JavaScript では実現できない機能を通じて Node.js の機能を強化する拡張機能を開発します。

Node .js 拡張子とは

Node.js 拡張子は、ファイル拡張子 .node を持つバイナリ ファイルです。本質的にはダイナミック リンク ライブラリであり、名前が変更された .dll として理解できます。または .so ファイル。

Node.js モジュール公式ドキュメント nodejs.cn/api/modules…

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

# の読み込みが必要になる場合があります。

Node.js 拡張機能 3 つの形式

拡張機能の種類基本的な説明Node.js 拡張機能のコードを変更します。 js バージョンの変更Node.js バージョンが変更されたときに再コンパイル#C を直接記述する ##NAN開発には NAN (Native Abstraction for Node.js) を使用しますいいえはいN-API開発にはnode-addon-apiを使用しますいいえ( ABI バージョンは一貫している必要があります)いいえ (ABI バージョンは一貫している必要があります)

1

2

3

4

5

直接写C++代码开发插件,当Node.js版本变化时引用的v8、libuv等库的版本可能发生变化,这些三方库的api也可能会变化,导致需要修改代码

 

NAN方式开发插件,引用nan.h需要在Node.js版本变化时重新编译

 

N-API方式调用Node.js稳定的二进制ABI接口(Application Binary Interface),只要ABI版本号一致就不需要重新编译复制代码

ログイン後にコピー

我们可以从Node.js官网历史版本下载页面,NODE_MODULE_VERSION看到Node.js版本与ABI版本的对应关系,nodejs.org/zh-cn/downl…

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

或者执行process.versions.modules查看ABI版本;process.versions查看相关配套版本:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

> process.versions

{

  node: '18.0.0',

  v8: '10.1.124.8-node.13',

  uv: '1.43.0',

  zlib: '1.2.11',

  brotli: '1.0.9',

  ares: '1.18.1',

  modules: '108',

  nghttp2: '1.47.0',

  napi: '8',

  llhttp: '6.0.4',

  openssl: '3.0.2+quic',

  cldr: '41.0',

  icu: '71.1',

  tz: '2022a',

  unicode: '14.0',

  ngtcp2: '0.1.0-DEV',

  nghttp3: '0.1.0-DEV'

}

ログイン後にコピー

我们来看下官方的Node.js扩展代码示例:github.com/nodejs/node… 对于N-API方式来说,c语言对应示例代码中的napi案例,c++对应示例代码中的node-addon-api案例,引用的头文件不同。

3-Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

安装依赖项

首先,需要安装依赖,按官方的说法可以使用windows-build-tools安装所有依赖。 nodejs.cn/api/n-api.h…

3-Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

但是,公司内网环境一直安装失败,按照文档尝试改了各种参数还是失败,可能是公司内网环境问题。如果你也遇到类似问题,可以尝试手动安装依赖。 github.com/felixrieseb…

手动安装步骤如下:

1.安装node-gyp

1

npm install -g node-gyp

ログイン後にコピー

2.安装Visual Studio Build Tools

可以参考node-gyp文档中的下载链接和步骤进行安装github.com/nodejs/node…

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

安装完成后更新npm配置,例如我安装的版本号是2022

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

1

npm config set msvs_version 2022

ログイン後にコピー

安装headers,头文件和Node.js版本是对应的,如果用nvm等工具切换过Node.js版本,请重新安装

1

node-gyp install --dist-url=http://mirrors.tools.huawei.com/Node.js/

ログイン後にコピー

此步骤会将node_api.h等头文件下载到本地,按Node.js版本号区分目录,例如:

1

C:\Users\z00443016\AppData\Local\node-gyp\Cache\18.0.0\include\node

ログイン後にコピー

配置IDE时会需要用到,当前可以忽略,后续的文章会再介绍具体配置

3.安装python

官网下载地址:www.python.org/downloads/

安装完成后将python和python/Scripts/目录加入到Path环境变量

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

更新npm配置,

1

npm config set python D:\runtime\python复制代码

ログイン後にコピー

从hellow world开始

以c++开发为例,复制官网示例到本地。github.com/nodejs/node…

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

执行npm install会自动调用node-gyp编译,生成build/Release/hello.node的目标文件,这个文件就是最终被js引用的扩展包,可以被require调用。

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

执行示例文件中的hello.js,会调用hello.cc中定义的hello方法输出'world'。

1

2

3

4

5

6

var addon = require('bindings')('hello');

 

// 或者直接require hello.node文件

// var addon = require('./build/Release/hello.node');

 

console.log(addon.hello()); // 'world'

ログイン後にコピー

如需重新编译,可以执行node-gyp rebuild,或者执行node-gyp help了解其他命令

至此,一个Node.js扩展demo就完成了。

抛出问题

Node.js使用非阻塞io的方式,在一个线程内可以异步处理多个任务,但是如果有一个cpu密集型的任务一直在处理,那么就会阻塞其他任务,响应时间变长。

Node.js官网的解释如下 nodejs.cn/learn/the-n…

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

开发Node.js扩展是解决问题的方式之一,最终使用什么方式去解决问题,需要基于我们对Node.js的理解,找到最佳实践。在上述场景中,我们可以使用libuv提供的线程池来异步处理这些cpu消耗较高的任务,从而不会阻塞其他任务的执行。

Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

当然了,web server并不适合处理cpu密集型任务,如果这个cpu密集型的任务调用频繁且耗时较高,就需要考虑从业务维度拆分,将任务挪到消息队列消费端执行。

环境配置

vsCode安装c++ intelliSense扩展应用

1Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

配置.vscode/c_cpp_properties.json,主要在includePath中配置好headers路径

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

{

    "configurations": [

        {

            "name""Win32",

            "includePath": [

                "${workspaceFolder}/**",

                "C:\Users\${userName}\AppData\Local\node-gyp\Cache\18.0.0\include\node",

                "D:\tool\nvm\v18.0.0\node_global\node_modules\node-addon-api"

            ],

            "defines": [

                "_DEBUG",

                "UNICODE",

                "_UNICODE"

            ],

            "cStandard""c17",

            "cppStandard""c++17",

            "intelliSenseMode""windows-msvc-x64"

        }

    ],

    "version": 4

}

ログイン後にコピー

配置.vscode/launch.json,完成调试配置就可以断点调试了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

{

    "version""0.2.0",

    "configurations": [

        {

            "name""c++ launch",

            "type""lldb",

            "request""launch",

            "program""D:\runtime\nodejs\node.exe",

            "args": ["${workspaceFolder}/src/hello.js"],

            "stopAtEntry": true,

            "cwd""${fileDirname}",

            "environment": [],

            "externalConsole": true,

            "MIMode""lldb",

            "setupCommands": [

                {

                    "description""为 gdb 启用整齐打印",

                    "text""-enable-pretty-printing",

                    "ignoreFailures": true

                }

            ]

        }

    ]

}

ログイン後にコピー

asyncWork扩展开发

可以参考官网示例,在项目中的Execute方法中添加自定义代码,不妨动手一式。github.com/nodejs/node…

node-gyp构建工具

node-gyp是Node.js扩展的构建工具,依赖python和Visual Studio Build Tools,基于google的gyp(Generate Your Projects)工具,chromium、v8等项目也在使用gyp构建。还可以使用CMake.js等工具进行编译构建。

1

2

npm config set msvs_version 2022

npm config set python D:\runtime\python

ログイン後にコピー

在package.json中定义"gypfile": true,执行npm install时会自动调用ndoe-gyp执行build操作。github.com/nodejs/node…

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

{

  "name""hello_world",

  "version""0.0.0",

  "description""Node.js Addons Example #1",

  "main""hello.js",

  "private": true,

  "dependencies": {

    "bindings""~1.2.1",

    "node-addon-api""^1.0.0"

  },

  "scripts": {

    "test""node hello.js"

  },

  "gypfile": true

}

ログイン後にコピー

node-pre-gyp预构建

由于编译是基于操作系统和硬件平台进行的,node-gyp构建生成的.node动态链接库不能跨平台,所以通常我们在使用Node.js扩展时以依赖包的形式引入项目,当执行npm install时,自动调用node-gyp生成当前环境可用的.node扩展包。

上述方式需要即时编译,无疑会拖慢npm install过程。于是就出现了node-pre-gyp预构建工具,直接从仓库下载当前环境可用的Node.js扩展包。

以Xprofiler为例,根据当前系统、硬件平台、Node.js的ABI版本生成下载地址,定义在package.json的binary字段:

1

2

3

4

5

6

7

"binary": {

    "module_name""xprofiler",

    "module_path""./build/binding/{configuration}/{node_abi}-{platform}-{arch}/",

    "remote_path""./v{version}/",

    "package_name""{module_name}-v{version}-{node_abi}-{platform}-{arch}.tar.gz",

    "host""https://github.com/X-Profiler/xprofiler/releases/download"

},

ログイン後にコピー

mirrors.tools.huawei.com/xprofiler/v…

1Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

其他形式的扩展 napi-rs

rust语言非常火爆,在Node.js开发领域也大有成为基础设施的趋势。比如,Node.js作者的新项目Deno就是用rust语言开发的;使用swc开发的编译工具替代Babel提升性能;rust支持编译成Webassembly,在前后台都能执行,具有很好的前景。

很多公司对rust语言十分重视,例如下图中的TOP公司已经成为rust基金会白金会员,用实际行动支持rust语言的发展。foundation.rust-lang.org/

1Node.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有

类似c++项目使用napi开发Node.js扩展,社区出现了napi-rs项目来支持rust语言开发Node.js扩展。github.com/napi-rs/nap…

直接调用动态链接库 node-ffi

FFI(Foreign Function Interface)语言交互接口,用一种编程语言写的程序能调用另一种编程语言写的函数,基本上成熟的编程语言都支持。使得我们可以在Node.js中直接调用c/c++、go、rust等语言编译生成的动态链接库,示例如下: github.com/node-ffi/no…

例如libmylibrary.dll或libmylibrary.so动态链接库的代码,c语言中的.h头文件描述:

1

2

3

4

5

double    do_some_number_fudging(double a, int b);

myobj *   create_object();

double    do_stuff_with_object(myobj *obj);

void      use_string_with_object(myobj *obj, char *value);

void      delete_object(myobj *obj);

ログイン後にコピー

js中使用ffi进行对应描述:

1

2

3

4

5

6

7

8

9

var ffi = require("ffi");

 

var MyLibrary = ffi.Library('libmylibrary', {

  "do_some_number_fudging": [ 'double', [ 'double''int' ] ],

  "create_object": [ myobjPtr, [] ],

  "do_stuff_with_object": [ "double", [ myobjPtr ] ],

  "use_string_with_object": [ "void", [ myobjPtr, "string" ] ],

  "delete_object": [ "void", [ myobjPtr ] ]

});

ログイン後にコピー

然后,就可以在js中调用了:

1

2

3

4

5

6

7

8

9

10

var res = MyLibrary.do_some_number_fudging(1.5, 5);

var fun_object = MyLibrary.create_object();

 

if (fun_object.isNull()) {

    console.log("Oh no! Couldn't create object!\n");

else {

    MyLibrary.use_string_with_object(fun_object, "Hello World!");

    var fun = MyLibrary.do_stuff_with_object(fun_object);

    MyLibrary.delete_object(fun_object);

}

ログイン後にコピー

更多node相关知识,请访问:nodejs 教程

v8、libuv、および開発用のその他のライブラリ Yes Yes

以上がNode.js 拡張機能を開発するにはどうすればよいですか?事前知識の共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:juejin.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート