跳至主要內容

Electron 內部原理:將 Node 作為函式庫使用

·4 分鐘閱讀

這是說明 Electron 內部原理的持續系列文章中的第二篇。如果您還沒有看過關於事件迴圈整合的第一篇文章,請先查看。

大多數人將Node用於伺服器端應用程式,但由於 Node 豐富的 API 集和蓬勃發展的社群,它也非常適合作為嵌入式函式庫。這篇文章說明如何在 Electron 中將 Node 作為函式庫使用。


建置系統

Node 和 Electron 都使用 GYP 作為其建置系統。如果要在應用程式內嵌入 Node,您也必須將它用作建置系統。

不熟悉 GYP?請在繼續閱讀這篇文章之前,先閱讀本指南

Node 的標誌

Node 原始碼目錄中的 node.gyp 檔案說明了如何建置 Node,以及許多 GYP 變數,這些變數控制啟用了 Node 的哪些部分以及是否開啟某些組態。

若要變更建置標誌,您需要在專案的 .gypi 檔案中設定變數。Node 中的 configure 指令碼可以為您產生一些常見的組態,例如執行 ./configure --shared 將產生一個 config.gypi,其中包含指示 Node 作為共用函式庫建置的變數。

Electron 不使用 configure 指令碼,因為它有自己的建置指令碼。Node 的組態定義在 Electron 根原始碼目錄中的 common.gypi 檔案中。

在 Electron 中,透過將 GYP 變數 node_shared 設定為 true 來將 Node 作為共用函式庫連結,因此 Node 的建置類型將從 executable 變更為 shared_library,並且不會編譯包含 Node main 進入點的原始碼。

由於 Electron 使用 Chromium 隨附的 V8 函式庫,因此不會使用 Node 原始碼中包含的 V8 函式庫。這是透過將 node_use_v8_platformnode_use_bundled_v8 都設定為 false 來完成的。

共用函式庫或靜態函式庫

在與 Node 連結時,有兩個選項:您可以將 Node 建置為靜態函式庫並將其包含在最終可執行檔中,或者您可以將其建置為共用函式庫並與最終可執行檔一起運送。

在 Electron 中,Node 長期以來都是作為靜態函式庫建置的。這使得建置變得簡單,能夠實現最佳的編譯器最佳化,並允許 Electron 在沒有額外 node.dll 檔案的情況下發佈。

然而,在 Chrome 切換為使用 BoringSSL 後,情況發生了變化。BoringSSL 是 OpenSSL 的分支,它移除了幾個未使用的 API 並變更了許多現有的介面。因為 Node 仍然使用 OpenSSL,如果它們連結在一起,編譯器會由於符號衝突而產生許多連結錯誤。

Electron 無法在 Node 中使用 BoringSSL,或者在 Chromium 中使用 OpenSSL,因此唯一的選擇是切換為將 Node 建置為共用函式庫,並在每個元件中隱藏 BoringSSL 和 OpenSSL 符號

此變更為 Electron 帶來了一些正面的副作用。在此變更之前,如果您使用原生模組,則無法在 Windows 上重新命名 Electron 的可執行檔,因為可執行檔的名稱已硬式編碼在匯入函式庫中。在將 Node 建置為共用函式庫後,此限制已消失,因為所有原生模組都已連結到 node.dll,而 node.dll 的名稱不需要變更。

支援原生模組

Node 中的原生模組運作方式是定義一個 Node 要載入的進入函式,然後從 Node 中搜尋 V8 和 libuv 的符號。這對嵌入者來說有點麻煩,因為預設情況下,當 Node 作為函式庫建置時,V8 和 libuv 的符號會被隱藏,而原生模組會因為找不到符號而載入失敗。

因此,為了使原生模組能夠運作,V8 和 libuv 的符號在 Electron 中被暴露出來。對於 V8,這是透過強制暴露 Chromium 組態檔中的所有符號來實現的。對於 libuv,則是透過設定 BUILDING_UV_SHARED=1 定義來實現的。

在您的應用程式中啟動 Node

在完成所有建置和連結 Node 的工作之後,最後一步是在您的應用程式中執行 Node。

Node 並未提供許多將自身嵌入到其他應用程式中的公開 API。通常,您只需呼叫node::Startnode::Init 來啟動一個新的 Node 實例。但是,如果您正在建置一個基於 Node 的複雜應用程式,則必須使用 node::CreateEnvironment 之類的 API 來精確控制每個步驟。

在 Electron 中,Node 以兩種模式啟動:在主進程中運行的獨立模式,這類似於官方的 Node 二進制檔;以及將 Node API 插入到網頁中的嵌入模式。詳細資訊將在未來的一篇文章中解釋。