Warning: Undefined variable $position in /home/pystyles/pystyle.info/public_html/wp/wp-content/themes/lionblog/functions.php on line 4897

Electron – チュートリアルその1 プロジェクトの作成

Electron – チュートリアルその1 プロジェクトの作成

概要

本記事では、Electron を使用したプロジェクトを作成するための手順について解説します。 Electron を使用したプロジェクトのテンプレートを作成する CLI ツールがいくつか存在しますが、今回はディレクトリが空の状態から作成していきます。

Electron

Electron は、HTML、CSS、JavaScript など Web テクノロジを使用して作成したフロントエンド画面をウィンドウに埋め込んで表示することで、デスクトップアプリケーションを作成できるフレームワークです。 Web サイトの画面を作るのと同様の技術でネイティブアプリを簡単につくれるのがメリットです。

手順

コード

コード全体は以下を参照ください。

electron-examples/01_electron-tutorial-create-project

1. パッケージを作成する

npm init コマンドで Node パッケージを作成します。

npm init
package name: (electron-sample) electron-example
version: (1.0.0) 1.0.0
description: Electron example
entry point: (index.js) main.cjs
test command:
git repository:
keywords:
author: papillon
license: (ISC) MIT

現時点で、ディレクトリ構成は以下のようになっています。

electron-example
├── node_modules
├── package-lock.json
└── package.json

2. Electron をインストールする

devDependencies として Electron を追加します。

npm install electron -D

3. 必要なファイルを作成する

エントリポイントとなる main.cjs を作成します。

main.cjs

const { app, BrowserWindow } = require("electron");

const createWindow = () => {
  // ウィンドウを作成する。
  const win = new BrowserWindow();
  // ウィンドウに HTML を表示する。
  win.loadFile("index.html");
};

// 初期化に成功した場合、ウィンドウを作成する。
app.whenReady().then(createWindow);

また、ウィンドウに表示する index.html を作成します。

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

現時点で、ディレクトリ構成は以下のようになっています。

electron-example
├── index.html
├── main.cjs
├── node_modules
├── package-lock.json
└── package.json

4. コマンドを追加する

npm start を実行したときに Electron を実行できるように、package.json にコマンドを追加します。 electron コマンドの引数にディレクトリを指定した場合、package.jsonmain キーに指定されたスクリプトファイルをエントリポイントとして、Electron が実行されます。

package.json

{
  "name": "electron-example-1",
  "version": "1.0.0",
  "description": "Electron example",
  "main": "main.cjs",
  "scripts": {
    "start": "electron ."
  },
  "author": "papillon",
  "license": "MIT",
  "devDependencies": {
    "electron": "^28.1.3"
  }
}

4. 実行する

npm start を実行すると、次のように HTML の画面を表示したウィンドウが起動します。

npm start

Electron

main.cjs について解説

const { app, BrowserWindow } = require("electron");

const createWindow = () => {
  // ウィンドウを作成する。
  const win = new BrowserWindow();
  // ウィンドウに HTML を表示する。
  win.loadFile("index.html");
};

// 初期化に成功した場合、ウィンドウを作成する。
app.whenReady().then(createWindow);

1. 必要なオブジェクト、クラスを import する

アプリケーション本体を表す app オブジェクト及びウィンドウを作成する BrowserWindow クラスを electron モジュールから読み込みます。

2. ウィンドウを作成する

new BrowserWindow() でウィンドウを作成します。ウィンドウの大きさなどを引数で指定できます。 これだけだと、中身が空のウィンドウが表示されるだけなので、BrowserWindow.loadFile() メソッドでウィンドウに表示する HTML ファイルを読み込みます。

3. Electron 初期化時にウィンドウを作成する

Electron の初期化後にウィンドウの作成を行うため、Electron が初期化されるときに実行される Promaise である app.whenReady() で、初期化成功後の処理として、ウィンドウを作成するコールバック関数を登録します。

付録: MacOS での記述

Windows や Linux では、ウィンドウを✕ボタンで閉じた場合、アプリが終了します。 一方、MacOS では✕ボタンでウィンドウを閉じると、ウィンドウが消えるがバックグラウンドでアプリ自体は動いた状態になっており、アプリがアクティブになった場合にウィンドウを再度表示する、といった挙動が一般的です。その挙動に倣う場合、先程の main.cjs を以下のように変更します。

const { app, BrowserWindow } = require("electron");

const createWindow = () => {
  // ウィンドウを作成する。
  const win = new BrowserWindow();

  // 画面を読み込む。
  win.loadFile("index.html");
};

app.whenReady().then(() => {
  createWindow(); // 初期化に成功した場合、ウィンドウを作成する。

  // アプリがアクティブになった場合
  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

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

1つ目の変更点は、すべてのウィンドウが閉じられた場合に生じる window-all-closed イベントを購読し、process.platformdarwin (MacOS) の場合は、アプリを終了しないように変更します。Electron のデフォルトの挙動は、すべてのウィンドウを閉じるとアプリ自体が終了します。

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();  // MacOS 以外の場合、アプリを終了する。
  }
});

2つ目の変更点は、アプリがアクティブになった場合に生じるイベント activate を購読し、表示されているウィンドウが1つもない場合、再度ウィンドウを表示するようにします。 これで、MacOS で一旦ウィンドウをすべて閉じてアプリがバックグラウンドで動いている状態のとき、アプリが再度アクティブになった場合に、ウィンドウが再び表示されるようになります。

app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) {
  createWindow();
}
});