Closed6

【ユニット勉強会】Electronについて調べたことを共有する

まさきちまさきち

Electronとは

JavaScript、HTML、CSS を使用してデスクトップアプリケーションを構築するフレームワークであり、 Windows、macOS、Linux で動作するクロスプラットフォームアプリ(iOS、Android、Windows、macOSなど異なるプラットフォーム上で、同じ仕様のアプリケーションを動かせるプログラムのこと)を作成することができる。
デスクトップアプリケーションの為、ブラウザ毎にコードを記載する必要がない。


Electronのコア構造

公式ドキュメント:「Chromium と Node.js をバイナリに組み込んでいる。」

  • Chromium:Chromiumは、Google Chromeウェブブラウザのオープンソース。Electronにおいて、Chromiumはウェブページやウェブアプリのレンダリングを担当。その為、Electronで作成されたアプリケーションは、HTML、CSS、JavaScriptを使ってUIの構築が可能。

  • Node.js:Electronにおいて、Node.jsは「メインプロセス」として動作し、アプリケーションのバックエンド的な役割を果たす。ファイルシステムの操作、ネットワーク通信、ネイティブAPIの呼び出し等、OSレベルの操作をJavaScriptから行うことが可能。

Electronアプリケーションをビルドすると、結果として得られるバイナリファイル(実行ファイル)には、ChromiumとNode.jsの両方が含まれ、Electronアプリは単独で実行可能である。

Electronがデスクトップアプリケーションの作成を可能にするために、ウェブブラウザのエンジン(Chromium)とサーバーサイドJavaScriptのランタイム(Node.js)を一つの実行ファイルに組み込んでいる。


Electronで作成されているアプリ

Discord、Facebook Messenger、Slack、Twitch、Visual Studio Code


まさきちまさきち

Electronのプロセスモデル

Electronではマルチプロセスモデルを採用している。
ブラウザでは、複数のウィンドウ (またはタブ) の管理や、サードパーティの拡張機能を読み込む処理を行っている。以前は単一のプロセスで実現していたが、1 つのウェブサイトがクラッシュしたりハングアップしたりすると、ブラウザ全体に影響が及ぶため、マルチプロセスモデルを採用。

Chromeのマルチプロセスモデルとよく似た機能をElectronでも有している。
https://www.google.com/googlebooks/chrome/


Electronは、起動時にNode.js側で実行するJavaScriptと、そのNode.jsから立ち上げたBrowserWindow(HTML)で実行するJavaScriptの、2つのJavaScriptが存在し、それぞれ別のプロセスで動作する。
前者を「メインプロセス」、後者を「レンダラプロセス」と呼ぶ。レンダラプロセスからメインプロセスへ必要に応じて処理を依頼する構造となっている。



メインプロセス

各 Electron アプリにつき一つのメインプロセスが存在しており、アプリケーションのエントリポイントとして機能する

  • CommonJS で記述される
  • 起動・終了といったアプリ全体の挙動を制御(BrowserWindow モジュールを使用して、アプリケーションウインドウを作成し管理)
  • Node.js 環境で動作しOS の機能を使用できる
  • src/main.tsでメインプロセスを定義している(アプリケーションのライフサイクルの制御)


レンダラープロセス

  • ECMAScript で記述される
  • 利用できる OS やブラウザの機能は、そのサイトやブラウザに与えられた権限内のみに限られる
  • src/render/*配下に配置


以下のコードでindex.htmlが読み込まれ、HTML ファイルが読み込まれた後の処理は Chromium(=ウェブブラウザ)が担当する = レンダラープロセス

const mainURL = `file://${__dirname}/render/index.html`;

function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });
  win.loadURL(mainURL);
  win.on("ready-to-show", () => {
    win.webContents.send("receive:message", "Hello Electron!!");
  });
  win.webContents.openDevTools();
}

// すべてのウィンドウが閉じられた場合にアプリを終了する
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

これらは独立した別個のプロセスであり、デフォルトではメインプロセスが持つ機能をレンダラープロセスからは利用することができない(OSの機能を無制限に利用できてしまう為)

その為、lectronではプロセス間通信を行うためのモジュールとして、ipcモジュールがあらかじめ定義されている。


まさきちまさきち

IPC 通信(プロセス間通信)

Electron ではメインプロセスとレンダラプロセス間の連携にプロセス間通信(IPC)を利用する。

Electron のプロセスモデルではメインプロセスとレンダラープロセスが異なる責務を担っており、UI からネイティブ API を呼び出したり、ネイティブメニューからウェブコンテンツの変更をトリガーしたりといった多くの共同タスクの実行には、IPC が唯一の方法となる。https://www.electronjs.org/ja/docs/latest/tutorial/ipc



プロセスの概念

  1. プロセスはコンピュータ上で実行されるプログラムの基本的な単位であり、その振る舞いや管理はオペレーティングシステムによって制御されている。
  2. 各プロセスは独自のメモリ領域を持ち、他のプロセスから独立して動作する。
  3. プロセスは実行のために必要なリソース(CPU時間、メモリ空間、ディスクスペースなど)をOSから割り当てられる。
  4. 通常、プロセスは互いのメモリ空間にアクセスすることができないが、プロセス間通信 (IPC)を通じて、プロセス間で情報を交換することが可能。



ipcMain と ipcRenderer

メインプロセスでのメッセージの受信には ipcMainモジュール、送信にはBrowserWindow.webcontents.sendインスタンスメソッドを利用する。

import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron";

const sendMainSend = async (msg: string): Promise<void> => {
  return await ipcRenderer.invoke("send:message", msg);
};

const receiveMessage = (callback: (msg: string) => void) => {
  ipcRenderer.on("receive:message", (_: IpcRendererEvent, msg: string) => {
    callback(msg);
  });
};

export interface IMainProcess {
  sendMainSend: typeof sendMainSend;
  receiveMessage: typeof receiveMessage;
}

contextBridge.exposeInMainWorld("electron", {
  sendMainSend,
  receiveMessage,
});


window.onload = () => {
  window.electron.receiveMessage((msg: string) => {
    const contents = <HTMLDivElement>document.getElementById("contents");
    contents.innerHTML = msg;
  });
  window.electron.sendMainSend("Start Renderer proces.");
};



https://www.mitsue.co.jp/knowledge/blog/apps/201512/08_1724.html

このスクラップは2023/08/26にクローズされました