跳到主要内容

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 的主入口点的源代码将不会被编译。

由于 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 中的原生模块的工作原理是为 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 插入到网页中的嵌入模式。详细信息将在以后的文章中解释。