Electron 內部原理:將 Node 作為函式庫使用
這是正在進行的系列文章中的第二篇,解釋 Electron 的內部原理。如果您還沒看過,請查看關於事件迴圈整合的第一篇文章。
大多數人將 Node 用於伺服器端應用程式,但由於 Node 豐富的 API 集和蓬勃發展的社群,它也非常適合作為嵌入式函式庫。這篇文章解釋了 Node 如何在 Electron 中作為函式庫使用。
建置系統
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
檔案中。
將 Node 與 Electron 連結
在 Electron 中,Node 被連結為共享函式庫,方法是將 GYP
變數 node_shared
設定為 true
,因此 Node 的建置類型將從 executable
變更為 shared_library
,並且包含 Node 的 main
入口點的原始碼將不會被編譯。
由於 Electron 使用 Chromium 附帶的 V8 函式庫,因此不使用 Node 原始碼中包含的 V8 函式庫。這是透過將 node_use_v8_platform
和 node_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 中的原生模組透過定義一個供 Node 載入的入口函數,然後從 Node 中搜尋 V8 和 libuv 的符號來工作。對於嵌入者來說,這有點麻煩,因為預設情況下,當將 Node 建置為函式庫時,V8 和 libuv 的符號會被隱藏,並且原生模組將無法載入,因為它們找不到符號。
因此,為了使原生模組能夠工作,V8 和 libuv 符號在 Electron 中被公開。對於 V8,這是透過強制公開 Chromium 配置檔案中的所有符號來完成的。對於 libuv,這是透過設定 BUILDING_UV_SHARED=1
定義來實現的。
在您的應用程式中啟動 Node
在完成所有建置和與 Node 連結的工作後,最後一步是在您的應用程式中執行 Node。
Node 沒有提供許多用於將自身嵌入到其他應用程式中的公開 API。通常,您只需調用 node::Start
和 node::Init
來啟動 Node 的新實例。但是,如果您要建置一個基於 Node 的複雜應用程式,您必須使用像 node::CreateEnvironment
這樣的 API 來精確控制每個步驟。
在 Electron 中,Node 以兩種模式啟動:在主進程中運行的獨立模式(類似於官方 Node 二進位檔),以及將 Node API 插入網頁的嵌入模式。這方面的詳細資訊將在未來的文章中解釋。