Node插件開發(1)-快速入門

在使用Electron開發客戶端時,如果現有Node模塊所提供的功能無法滿足需求,我們可以使用C++開發自定義的Node模塊,也稱插件(addon)。

Node.js插件的擴展名為.node,是二進制文件,其本質上是動態鏈接庫重命名而來,在Windows平臺是.dll文件,Linux/Unix平臺是.so文件。

1. 選擇Node-API

開發Node.js擴展的方式有三種:

  • Node-API(以前叫N-API)
  • nan
  • 直接使用v8、libuv等庫進行開發

除非是為了使用 Node-API 未公開的接口,否則建議使用 Node-API 進行開發。

因為Node-API是二進制(ABI)兼容的,它將底層JavaScript引擎與上層插件隔離開了,JavaScripty引擎的修改不會影響我們開發的上層插件,我們基于某個版本編譯的插件在不需要重新編譯的情況下,就可以運行在其他版本的Node.js中。

2. 安裝編譯環境

Node插件使用C++開發,因此在不同的系統上采用不同的編譯環境。
在Linux環境通常使用GCC和LLVM;

Mac環境通常使用Xcode;

Windows環境通常使用Visual Studio,如果不想安裝完整的Visual Studio,可以使用如下命令僅安裝必要的工具鏈:

npm install --global windows-build-tools 

Node插件通常使用node-gyp進行編譯,node-gyp基于Google的gyp-next構建系統,node-gyp已經與npm捆綁在一起,但我們在使用node-gyp之前還需要先安裝Python。

至此Node插件開發的環境已經搭建完成。

3.搭建工程

本文以在Windows下開發Node插件為例,其他系統環境在編譯選項方面略有不同

3.1 package.json

{"name": "node-addson-sample","version": "1.0.0","private": true,"description": "A sample node addson sample","dependencies": {"bindings": "^1.5.0","node-addon-api": "^7.1.0"},"scripts": {"build-debug": "node-gyp --debug --arch=x64 configure rebuild","build-release": "node-gyp --release --arch=x64 configure rebuild","test": "node test.js"}
}

使用npm install安裝依賴項。

各個依賴項的作用如下:

  • node-addon-api用于提供了Node-API相關的頭文件;

  • bindings用于幫助插件開發者快速導入編譯后的.node插件,方便調試,這個依賴是非必須;

build-debugbuild-release腳本分別用于編譯Debug和Release版本的插件;

test腳本用于執行測試用例;

32位插件

指定arch為ia32(--arch=ia32)就可以編譯32位版本的Node插件。

需要注意:64位版本Node.js只能加載64位的Node插件,32位版本的Node.js也只能加載32位的Node插件,否則會報錯:

Error: \\?\D:\node-addon-sample\build\Debug\node-addon-sample.node is not a valid Win32 application.

3.2 編譯腳本

新建binding.gyp文件,內容如下:

{"targets": [{"target_name": "node-addson-sample", # ***.node"cflags!": [ "-fno-exceptions" ],"cflags_cc!": [ "-fno-exceptions" ],# 指定需要編譯的源文件"sources": [ "main.cpp" ],"include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],# 預編譯宏"defines": [ "NAPI_CPP_EXCEPTIONS", # 在Node-API中啟用C++異常],"conditions": [[# Windows平臺編譯選項"OS == 'win'", {"configurations": {# Debug編譯選項"Debug": {# 預編譯宏"defines": [ "DEBUG", "_DEBUG" ],"cflags": [ "-g", "-O0" ],"conditions": [["target_arch=='x64'", {"msvs_configuration_platform": "x64",}],],"msvs_settings": {"VCCLCompilerTool": {"RuntimeLibrary": 1, # /MTd"Optimization": 0, # /Od, no optimization"MinimalRebuild": "false","OmitFramePointers": "false","BasicRuntimeChecks": 3, # /RTC1"AdditionalOptions": ["/EHsc"],},"VCLinkerTool": {"LinkIncremental": 2, # Enable incremental linking# 附加依賴庫"AdditionalDependencies": [],},},# 附加包含目錄"include_dirs": [],},# Debug編譯選項"Release": {# 預編譯宏"defines": [ "NDEBUG" ],"msvs_settings": {"VCCLCompilerTool": {"RuntimeLibrary": 0, # /MT"Optimization": 3, # /Ox, full optimization"FavorSizeOrSpeed": 1, # /Ot, favour speed over size"InlineFunctionExpansion": 2, # /Ob2, inline anything eligible"WholeProgramOptimization": "false", # Dsiable /GL, whole program optimization, needed for LTCG"OmitFramePointers": "true","EnableFunctionLevelLinking": "true","EnableIntrinsicFunctions": "true","RuntimeTypeInfo": "false","ExceptionHandling": "2", # /EHsc"AdditionalOptions": ["/MP", # compile across multiple CPUs],"DebugInformationFormat": 3,"AdditionalOptions": [],},"VCLibrarianTool": {"AdditionalOptions": ["/LTCG", # link time code generation],},"VCLinkerTool": {"LinkTimeCodeGeneration": 1, # link-time code generation"OptimizeReferences": 2, # /OPT:REF"EnableCOMDATFolding": 2, # /OPT:ICF"LinkIncremental": 1, # disable incremental linking# 附加依賴庫"AdditionalDependencies": [],},},# 附加包含目錄"include_dirs": [],}}},]]}]
}

binding.gyp中的編譯選項大多與特定平臺的編譯器有關,具體可以查閱相關編譯器文檔,如Windows平臺可以查詢MSVC文檔。

node-gyp官方提供了一些示例,我們可以從這些示例中獲取不少靈感:

binding.gyp-files-in-the-wild

GYP官方文檔:

https://gyp.gsrc.io/docs/UserDocumentation.md

3.3 第一個API

現在新建main.cpp,在該文件中定義我們的第一個API,API名為Add,支持傳入2個整數參數,返回整數相加的和。

#include <napi.h>// 同步調用
// 計算兩個整數相加結果并返回
Napi::Number Add(const Napi::CallbackInfo& info) {Napi::Env env = info.Env();if (info.Length() != 2)throw Napi::TypeError::New(env, "Wrong number of arguments");if (!info[0].IsNumber() || !info[1].IsNumber())throw Napi::TypeError::New(env, "Wrong arguments");const int ret = info[0].ToNumber().Int32Value() + info[1].ToNumber().Int32Value();return Napi::Number::New(env, ret);
}

在定義完API之后,還需要將API導出,在文件末尾添加如下代碼:

// 導出函數
Napi::Object Init(Napi::Env env, Napi::Object exports) {exports.Set(Napi::String::New(env, "Add"), Napi::Function::New(env, Add));return exports;
}NODE_API_MODULE(addon, Init)

如果忘記導出API,加載Node插件時會報錯:

Error: Module did not self-register: '\\?\D:\node-addson-sample\build\Debug\node-addson-sample.node'.

現在執行npm run build-debug編譯Debug版本插件,編譯生成的node插件路徑為build\Debug\node-addson-sample.node

3.4 測試用例

新建test.js,測試代碼如下:

const sample = require("bindings")("node-addson-sample.node");console.log(sample.Add(100, 200)); // 輸出300

使用bindings模塊可以不用考慮插件的具體位置,該模塊會自動幫我們在項目目錄下遍歷查找。

4. 數據類型

napi.h頭文件中聲明很多繼承自Napi::Value的子類,這些類分別對應JavaScript中的數據類型,如:

  • Napi::Boolean -> Boolean
  • Napi::Number -> Number
  • Napi::String -> String
  • Napi::Function -> Function
  • Napi::Symbol -> Symbol
  • Napi::Array -> Array
  • Napi::Object -> Object

Node-Api還定義Promise、Date、Buffer等數據類型。

4.1 Null和Undefined

Null和Undefined比較特殊,沒有定義專門的類,需要使用Env類的成員函數返回。

env.Null()env.Undefined()

4.2 創建對象

可以通過下面兩種方式創建指定類型的對象,以創建Boolean類型為例:

Napi::Boolean::New(env, true)
Napi::Value::From(env, false)

以創建一個對象數組為例介紹對象和數組的使用方法:

Napi::Array result = Napi::Array::New(env);
for (size_t i = 0; i < 3; i++) {Napi::Object obj = Napi::Object::New(env);obj.Set(Napi::String::New(env, "filePath"), Napi::String::New(env, "/root/" + std::to_string(i) + ".txt"));obj.Set(Napi::String::New(env, "fileSize"), Napi::Number::New(env, i * 100));result.Set(Napi::Number::New(env, i), obj);
}

4.3 類型校驗

Napi::Value提供了若干方法用于判斷當前對象是否為指定類型,如:

  • IsUndefined
  • IsNull
  • IsBoolean
  • IsNumber
  • IsString
  • IsSymbol
  • IsArray
  • IsObject
  • IsFunction
  • IsPromise
  • IsBuffer

5. 異常

可以在編譯腳本binding.gyp中通過預編譯宏指定是否啟用C++異常:

NAPI_CPP_EXCEPTIONSNAPI_DISABLE_CPP_EXCEPTIONS

如果啟用C++異常,則Napi::Error會繼承自std::exception。

class Error : public ObjectReference
#ifdef NAPI_CPP_EXCEPTIONS,public std::exception
#endif  // NAPI_CPP_EXCEPTIONS
...

在啟動C++異常的情況下,從Node插件拋出異常的方式如下:

throw Napi::TypeError::New(env, "Wrong number of arguments");

當前函數throw語句后面的流程將會中斷執行。

TypeError繼承自Error,通常用于表示與類型錯誤相關的異常。類似的錯誤類型還有RangeError等,也可以直接拋出Error類型的錯誤:

throw Napi::Error::New(env, "Wrong number of arguments");

在沒有啟動C++異常的情況下,從Node插件拋出異常的方式如下,拋出異常后需要使用return語句終止下面流程的執行:

Napi::TypeError::New(env, "Wrong number of arguments").ThrowAsJavaScriptException();
return;

更多優質內容歡迎訪問我的個人站點:https://jiangxueqiao.com

Node-API官方文檔:node-addon-api doc

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718701.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718701.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718701.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于springboot+vue的響應式企業員工績效考評系統(源碼+論文)

文章目錄 前言 一、功能設計 1 普通員工功能 2 主管功能 3 系統管理員功能 4 評分標準功能 5 PC端與手機端 6 制圖 二、功能實現 普通員工 1普通員工登錄 2公告板塊 3日志板塊 主管 1主管登錄 2公告板塊 3日志板塊 4績效評分板塊 5個人信息板塊 系統管理員…

TypeScript 日期格式化工具方法

工具方法 創建工具文件&#xff1a;util.ts /*** 獲取時間并格式化函數* param M 格式模板 如: YYYY-MM-DD ...* param Time 可選傳入時間參數 默認為 Now*/ export const getFormatDate (M: string, Time: Date | null | string | number null) > {let date: Date Tim…

在 Linux 環境下安裝 Kibana

目錄 一、Kibana 是什么 二、在 Linux 環境下安裝 Kibana 1、下載安裝包 2、解壓 3、修改 Kibana的配置文件 config/kibana.yml 4、啟動 5、瀏覽器登錄 Kibana 6、測試查詢 一、Kibana 是什么 Kibana 是通向 Elastic 產品集的窗口。 它可以在 Elasticsearch 中對數據進…

品牌推廣的兩種飛輪:非酋飛輪與歐皇飛輪

在品牌推廣的世界里&#xff0c;存在著兩種截然不同的飛輪效應&#xff0c;我們稱之為“非酋飛輪”與“歐皇飛輪”。這兩種飛輪象征著品牌發展的兩種不同路徑和策略&#xff0c;而迅騰文化則以其獨特的“繁”的原則&#xff0c;巧妙地將這兩種飛輪結合&#xff0c;助力品牌形成…

Linux安裝JumpServer并結合內網穿透實現公網訪問本地服務

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

Kubernetes 學習總結(46)—— Pod 不停重啟問題分析與解決

我們在做性能測試的時候&#xff0c;往往會發現我們的pod服務&#xff0c;頻繁重啟&#xff0c;通過kubectl get pods 命令&#xff0c;我們來逐步定位問題。 現象:running的pod&#xff0c;短時間內重啟次數太多。 定位問題方法:查看pod日志 kubectl get event …

【Element】實現基于 Element UI el-tabs 的左右滑動動畫

實現基于 Element UI el-tabs 的左右滑動動畫 引言 在構建現代 web 應用時&#xff0c;為用戶提供平滑的動畫效果是提升用戶體驗的關鍵。本篇博客將詳細介紹如何在使用 Vue 以及 Element UI 時&#xff0c;實現一個具有左右滑動效果的 tab 切換動畫。 使用 el-tabs 創建 tab…

Flutter 中的 SliverGrid 和 GridView:區別與使用場景

在 Flutter 中&#xff0c;SliverGrid 和 GridView 都是用于展示網格布局的組件&#xff0c;但它們有著不同的特點和適用場景。本文將介紹它們之間的區別以及在實際開發中的使用場景。 SliverGrid 和 GridView 的區別 SliverGrid&#xff1a; SliverGrid 是 CustomScrollView …

第十五屆藍橋杯第三期模擬賽題單

目錄 第一題&#xff1a; 第二題&#xff1a; 第三題&#xff1a; 第四題: 第五題&#xff1a; 第六題&#xff1a; 第七題 第八題 第九題 第十題 第一題 【問題描述】 請問 2023 有多少個約數&#xff1f;即有多少個正整數&#xff0c;使得 2023 是這個正整數的整數倍…

FolkMQ 是怎樣進行消息的事務處理?

FolkMQ 提供了二段式提交的事務提交的機制&#xff08;TCC 模型&#xff09;。允許生產者在發送消息時綁定到一個事務中并接收事務的管理&#xff0c;以確保消息的原子性&#xff08;要么全成功&#xff0c;要么全失敗&#xff09;。在 FolkMQ 中&#xff0c;事務是通過 MqTran…

1、EmlogCms代碼審計

一、SQL注入 1、后臺標簽刪除處存在1處sql注入 漏洞條件 ● 漏洞url: http://emlog6.0.com/admin/tag.php?actiondell_all_tag ● 漏洞參數&#xff1a;tag[xx] ● 是否存在限制&#xff1a;無 ● 是否還有其他條件&#xff1a;actiondell_all_tag,token復現 POST /admin…

擼chatgpt3.5 api backend-api 對接wxbot

功能是實現 web 轉api 對接wxbot用&#xff0c; 直接上代碼&#xff0c; 1.獲取wss url def get_register_websocket():# 請求頭url "https://chat.openai.com/backend-api/register-websocket"payload {}headers {Authorization: Bearer eyJhbGxxxxxxxxxxxxx…

docker的網絡配置

文章目錄 1、網絡模式1.1、bridge模式(默認模式)1.2、host模式 2、bridge模式3、自定義網絡 1、網絡模式 Docker在創建容器時有四種網絡模式&#xff1a;bridge/host/container/none&#xff0c;bridge為默認不需要用–net去指定&#xff0c;其他三種模式需要在創建容器時使用…

【力扣 - 最長連續數組】

題目描述 給定一個未排序的整數數組 nums &#xff0c;找出數字連續的最長序列&#xff08;不要求序列元素在原數組中連續&#xff09;的長度。 請你設計并實現時間復雜度為 O(n) 的算法解決此問題。 示例 1&#xff1a; 輸入&#xff1a;nums [100,4,200,1,3,2] 輸出&…

Linux命令:uniq命令和wc命令

目錄 1 uniq命令1.1 uniq簡介1.2說明1.3案例1、默認輸出2、輸出重復行3、比較一行中的部分字符4、忽略大小寫5、只顯示唯一的行 2.4 uniq和sort命令配合使用1、文本統計2、統計IP連接數并排序 2 wc命令2.1 wc簡介2.2 說明2.3 案例1、默認輸出2、輸出字節、字符數、單詞數 總結 …

案例介紹:汽車維修系統的信息抽取技術與數據治理應用(開源)

一、引言 在當今汽車產業的快速發展中&#xff0c;軟件已經成為提升車輛性能、安全性和用戶體驗的關鍵因素。從車載操作系統到智能駕駛輔助系統&#xff0c;軟件技術的進步正在重塑我們對汽車的傳統認知。我有幸參與了一個創新項目&#xff0c;該項目專注于開發和集成先進的汽…

關于 svg path 路徑坐標 精度誤差問題

<svg width"2838.739990" height"2482.179932" viewBox"0 0 2838.74 2482.18" fill"none" xmlns"http://www.w3.org/2000/svg" xmlns:xlink"http://www.w3.org/1999/xlink"><path id"矢量 12"…

原理篇-- 定時任務xxl-job-服務端(admin)項目啟動過程--JobRegistryHelper 初始化 (4)

文章目錄 前言一、JobRegistryHelper 作用&#xff1a;二、JobRegistryHelper 源碼介紹&#xff1a;2.1 初始化start() 方法&#xff1a;2.1.1 registryOrRemoveThreadPool 執行器注冊和移除&#xff1a;2.1.2 registryMonitorThread 執行器注冊監控線程&#xff1a; 2.2 toSto…

折線圖實現柱狀陰影背景的demo

這個是一個由官網的基礎折線圖實現的流程&#xff0c;將涉及到的知識點附上個人淺薄的見解&#xff0c;源碼在最后&#xff0c;需要的可自取。 折線圖 成果展示代碼注解參數backgroundColordataZoomlegendtitlexAxisyAxisgridseries 源碼 成果展示 官網的基礎折線圖&#xff…

貓耳語音下載(mediadown)

貓耳語音下載(mediadown) 一、介紹 貓耳語音下載,能夠幫助你下載貓耳音頻節目。如果你是會員,它還能幫你下載會員節目。 二、下載地址 下載:貓耳語音下載(mediadown) 百度網盤下載:貓耳語音下載(mediadown) 三、安裝教程 將下載的文件解壓到D:\xibinhui,D:\Pr…