Skip to main content

Electron Internals: Using Node as a Library

· 4 min read

This is the second post in an ongoing series explaining the internals of Electron. Schaue dir den ersten Beitrag über die Integration von Ereignis-Schleifen an, falls du es noch nicht getan hast.

Most people use Node for server-side applications, but because of Node's rich API set and thriving community, it is also a great fit for an embedded library. This post explains how Node is used as a library in Electron.


Build system

Sowohl Knoten als auch Electron verwenden GYP als Build-Systeme. If you want to embed Node inside your app, you have to use it as your build system too.

New to GYP? Lies diese Anleitung bevor du in diesem Beitrag weitermachst.

Node's flags

Der Knoten. yp Datei im Quellcode-Verzeichnis von Node beschreibt, wie Knoten gebaut wird, zusammen mit vielen GYP Variablen steuern, welche Teile von Knoten aktiviert sind und ob bestimmte Konfigurationen geöffnet werden sollen.

To change the build flags, you need to set the variables in the .gypi file of your project. The configure script in Node can generate some common configurations for you, for example running ./configure --shared will generate a config.gypi with variables instructing Node to be built as a shared library.

Electron does not use the configure script since it has its own build scripts. Die Konfigurationen für den Knoten sind in der common.gypi Datei im Wurzel-Quellcode-Verzeichnis definiert.

In Electron, Node is being linked as a shared library by setting the GYP variable node_shared to true, so Node's build type will be changed from executable to shared_library, and the source code containing the Node's main entry point will not be compiled.

Since Electron uses the V8 library shipped with Chromium, the V8 library included in Node's source code is not used. This is done by setting both node_use_v8_platform and node_use_bundled_v8 to false.

Shared library or static library

When linking with Node, there are two options: you can either build Node as a static library and include it in the final executable, or you can build it as a shared library and ship it alongside the final executable.

In Electron, Node was built as a static library for a long time. This made the build simple, enabled the best compiler optimizations, and allowed Electron to be distributed without an extra node.dll file.

Dies änderte sich jedoch nach dem Wechsel von Chrome auf BoringSSL. BoringSSL ist ein Fork von OpenSSL das mehrere ungenutzte APIs entfernt und viele vorhandene Schnittstellen ändert. Because Node still uses OpenSSL, the compiler would generate numerous linking errors due to conflicting symbols if they were linked together.

Electron konnte BoringSSL im Knoten nicht verwenden oder OpenSSL in Chromium, verwenden damit die einzige Option war, auf den Knoten als freigegebene Bibliothek zu wechseln, und die BoringSSL und OpenSSL Symbole in den einzelnen Komponenten verbergen.

This change brought Electron some positive side effects. Before this change, you could not rename the executable file of Electron on Windows if you used native modules because the name of the executable was hard coded in the import library. After Node was built as a shared library, this limitation was gone because all native modules were linked to node.dll, whose name didn't need to be changed.

Supporting native modules

Native Module in Knotenarbeit, indem Sie eine Eintragsfunktion für Knoten definieren, und durchsuchen Sie dann die Symbole von V8 und libuv von Node. This is a bit troublesome for embedders because by default the symbols of V8 and libuv are hidden when building Node as a library and native modules will fail to load because they cannot find the symbols.

So in order to make native modules work, the V8 and libuv symbols were exposed in Electron. Für V8 geschieht dies, indem alle Symbole in der Chromiums-Konfigurationsdatei erzwingt. Für libuv wird erreicht, indem die BUILDING_UV_SHARED=1 Definition gesetzt wird.

Starting Node in your app

After all the work of building and linking with Node, the final step is to run Node in your app.

Node doesn't provide many public APIs for embedding itself into other apps. Normalerweise können Sie einfach node::Start und node::Init aufrufen, um eine neue Knoten-Instanz zu starten. However, if you are building a complex app based on Node, you have to use APIs like node::CreateEnvironment to precisely control every step.

In Electron, Node is started in two modes: the standalone mode that runs in the main process, which is similar to official Node binaries, and the embedded mode which inserts Node APIs into web pages. The details of this will be explained in a future post.