N-API模塊的編寫與發佈

前言

作爲nodejs的底層開發語言,c++具有高性能、複用性好等優勢,c++編寫的chrome v8引擎與libuv、http-parser、zlib等等一起構成了現在大前端技術的基礎——nodejs。

nodejs也提供了編寫c++擴展以提高性能的方法。但是原生 C++ 模塊的開發一直是一個被人冷落的角落,其中一部分原因在於Node程序員有一部分來自於前端,c++的學習成本很高可能沒有系統的C++知識,另一部分原因是node的c++擴展機制很複雜,需要理解v8的各種概念,包括隔離示例、虛擬機、上下文、句柄、內存回收(gc)、模板等等。更難過的是,隨着版本的更替,一個編譯好的插件發佈沒多久,就會因爲版本的不兼容不得不重新編譯以適應版本。

關於C++插件開發的發展史,可以參考以下這篇文章

從暴力到 NAN 再到 NAPI——Node.js 原生模塊開發方式變遷

N-API簡介

N-API是node8.3新增的實驗性特性,在node10中正式啓用,下面是官網的說明

N-API (pronounced N as in the letter, followed by API) is an API for building native Addons. It is independent from the underlying JavaScript runtime (ex V8) and is maintained as part of Node.js itself. This API will be Application Binary Interface (ABI) stable across versions of Node.js. It is intended to insulate Addons from changes in the underlying JavaScript engine and allow modules compiled for one version to run on later versions of Node.js without recompilation.

Addons are built/packaged with the same approach/tools outlined in the section titled C++ Addons. The only difference is the set of APIs that are used by the native code. Instead of using the V8 or Native Abstractions for Node.js APIs, the functions available in the N-API are used.

N -API是一個構建本地擴展插件的API。它並不依賴於JavaScript運行環境(例如v8)而是作爲Node.js自身的組建的一部分運行。在Node.js當中這個API將會作爲應用程序二進制接口(ABI) 穩定存在。它的目的是爲了可以讓插件直接與JS引擎底層交互並允許它們編譯一次之後無需爲每個新版本的Node重新編譯。

這個插件的構建、打包和使用與一般C++插件相同。惟一的不同的是這組API調用Node.js原生對象,而不是使用v8或者本地抽象的Node.js API。

相關準備

以下均爲win環境

方法一:

按先後順序全局安裝 windows-build-toolsnode-gyp 和 node-pre-gyp-github

npm install --global --production windows-build-tools
npm install -g node-gyp
 npm install -g node-pre-gyp-github

windows-build-tools
windows環境下,node-gyp工作必須工具

node-gyp
c++擴展編譯工具

node-pre-gyp-github
二進制包分發工具node-pre-gyp在github的實現
解決部分使用環境下缺少c++編譯工具的問題,例如使用tag以slim和alpine結尾的node鏡像運行的容器中
安裝完成之後需要設置相關環境變量,具體參照node-pre-gyp-github

方法二:

安裝docker for windows,具體安裝方法自行參考官網

編寫

n-api擴展模塊中代碼的編寫可以參考官方中文文檔官方示例(node10),binding.gyp 文件的編寫可以參考這個頁面所列出來的模塊的binding.gyp。官方示例爲使用 node_api.h頭文件,在最新的node12預覽版中,可以使用新增的 node_api.h 所引用的  js_native_api.h 頭文件。與 node_api.h 相比 使用 js_native_api.h 編寫的c++擴展無法使用nodejs中的一些特性,目前發現無法直接調用的功能包括Buffer對象、獲取任務隊列、異步操作,意圖將js標準api與node特定api隔離,降低耦合性,具體可以參考這個PR

這是我所寫的一個例子,傳送門:https://github.com/zhouzhi3859/napi_example

克隆下來之後,在文件目錄運行 npm install 之後會看見除了node_modules與package-lock.json之外,還多出來binding文件夾,裏面存放的正是直接從github上下載的 .node 結尾的文件,不需要本地編譯。

發佈

以下命令運行均運行於當前工程目錄下

上面第一種環境中,編譯發佈針對win:

npm run build
npm run package  
npm run publish

上面第二種環境中:

docker pull node     // 不能用tag以slim與alpine結尾的鏡像,這些鏡像缺少c++擴展編譯環境
docker run -it -v $pwd:/root --name napi_example_build -w /root node bash    // 進入容器中
容器中執行以下命令
npm run build
npm run package  
npm run publish

然後退出容器

接下來就可以按照正常的npm模塊發佈流程發佈所編寫的c++擴展了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章