メインコンテンツへスキップ

Electronの内部構造: ライブラリとしてのNodeの使用

·4分で読めます

これは、Electronの内部構造について説明する連載の2番目の投稿です。まだ読んでいない場合は、イベントループの統合に関する最初の投稿を確認してください。

ほとんどの人はサーバーサイドアプリケーションにNodeを使用していますが、Nodeの豊富なAPIセットと活気のあるコミュニティのため、組み込みライブラリにも最適です。この投稿では、NodeがElectronでライブラリとしてどのように使用されているかを説明します。


ビルドシステム

NodeとElectronの両方で、ビルドシステムとしてGYPを使用しています。Nodeをアプリに埋め込みたい場合は、ビルドシステムとしても使用する必要があります。

GYPは初めてですか?この投稿の続きを読み進める前に、このガイドをお読みください。

Nodeのフラグ

Nodeのソースコードディレクトリにあるnode.gypファイルには、Nodeのビルド方法と、Nodeのどの部分を有効にするか、特定の構成を開くかどうかを制御する多くのGYP変数が記述されています。

ビルドフラグを変更するには、プロジェクトの.gypiファイルに変数を設定する必要があります。Nodeのconfigureスクリプトは、いくつかの一般的な構成を生成できます。たとえば、./configure --sharedを実行すると、Nodeを共有ライブラリとしてビルドするように指示する変数を含むconfig.gypiが生成されます。

Electronには独自のビルドスクリプトがあるため、configureスクリプトは使用しません。Nodeの構成は、Electronのルートソースコードディレクトリにあるcommon.gypiファイルで定義されています。

Electronでは、GYP変数node_sharedtrueに設定することにより、Nodeが共有ライブラリとしてリンクされているため、Nodeのビルドタイプがexecutableからshared_libraryに変更され、Nodeのmainエントリポイントを含むソースコードはコンパイルされません。

ElectronはChromiumに同梱されているV8ライブラリを使用するため、Nodeのソースコードに含まれているV8ライブラリは使用されません。これは、node_use_v8_platformnode_use_bundled_v8の両方をfalseに設定することで行われます。

共有ライブラリまたは静的ライブラリ

Nodeとリンクする場合、2つのオプションがあります。Nodeを静的ライブラリとしてビルドして最終的な実行可能ファイルに含めるか、共有ライブラリとしてビルドして最終的な実行可能ファイルと一緒に出荷することができます。

Electronでは、Nodeは長い間静的ライブラリとしてビルドされていました。これにより、ビルドが簡単になり、最適なコンパイラの最適化が可能になり、Electronを余分なnode.dllファイルなしで配布することができました。

ただし、これはChromeがBoringSSLを使用するように切り替えた後に変更されました。BoringSSLは、いくつかの未使用のAPIを削除し、既存の多くのインターフェイスを変更するOpenSSLのフォークです。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は2つのモードで起動します。公式のNodeバイナリと同様にメインプロセスで実行されるスタンドアロンモードと、WebページにNode APIを挿入する埋め込みモードです。この詳細については、今後の記事で説明します。