初めてのアプリのビルド
これは Electron チュートリアルの 2 章 です。
学習目標
このチュートリアルでは、Electron プロジェクトのセットアップと、最小限のスターターアプリケーションの作成方法を学びます。 この章の終わりには、ターミナルから開発モードで動作する Electron アプリを実行できるようになるでしょう。
プロジェクトのセットアップ
Windows マシンをご利用の方は、Windows Subsystem for Linux (WSL) を使用してアプリケーションを実行しようとすると問題が発生します。このチュートリアルに従う際にはご利用をお控えください。
npm プロジェクトの初期化
Electron アプリは npm を利用して組み上げられ、package.json ファイルをエントリポイントとします。 まずフォルダを作成し、その中で npm init
を実行して npm パッケージを初期化します。
- npm
- Yarn
mkdir my-electron-app && cd my-electron-app
npm init
mkdir my-electron-app && cd my-electron-app
yarn init
このコマンドは、package.json のいくつかのフィールドに対する設定を確認します。 このチュートリアルの目的上、以下のルールに従ってください。
- エントリポイント は
main.js
にしてください (後でそのファイルを作成します)。 - author, license, and description can be any value, but will be necessary for packaging later on.
次に、Electron をアプリのdevDependencies にインストールします。これは、本番環境では必要ない外部の開発専用パッケージの依存関係のリストです。
これは本番環境のコードで Electron API を実行していることから、直感に反していると思われるかもしれません。 しかし、パッケージ化されたアプリには Electron のバイナリがバンドルされるため、本番環境時の依存関係として指定しないでください。
- npm
- Yarn
npm install electron --save-dev
yarn add electron --dev
パッケージを初期化して Electron をインストールすると、package.json ファイルは以下のようになるでしょう。 さらに Electron の実行形式などが含まれた node_modules
フォルダに加えて、インストールする正確な依存関係のバージョンを指定する package-lock.json
ロックファイルも生成されるはずです。
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
If installing Electron directly fails, please refer to our Advanced Installation documentation for instructions on download mirrors, proxies, and troubleshooting steps.
.gitignore の追加
.gitignore
ファイルでは、Git での追跡を避けるファイルやディレクトリを指定します。 GitHub の Node.js gitignore テンプレート をコピーしてプロジェクトのルートフォルダに配置しておけば、プロジェクトの node_modules
フォルダのコミットを回避できます。
Electron アプリの実行
Read Electron's process model documentation to better understand how Electron's multiple processes work together.
どのような Electron アプリケーションのエントリポイントも、package.json で定義した main
スクリプトになります。 このスクリプトは メインプロセス を制御します。メインプロセスは Node.js 環境で動作し、アプリのライフサイクル制御、ネイティブインターフェースの表示、特権操作、レンダラープロセス (後述) の管理を担います。
最初の Electron アプリを作成する前に、まず小さなスクリプトを使用して、メインプロセスのエントリポイントが正しく設定されていることを確認します。 プロジェクトのルートフォルダに main.js
というファイルを作成し、以下の 1 行を記述します。
console.log('Hello from Electron 👋')
Because Electron's main process is a Node.js runtime, you can execute arbitrary Node.js code with the electron
command (you can even use it as a REPL). このスクリプトを実行するには、package.json のscripts
フィールド内に start
コマンドとして electron .
を追加します。 このコマンドは、Electron の実行形式に対して、カレントディレクトリにある main スクリプトを探して開発モードで実行するように指示します。
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
- npm
- Yarn
npm run start
yarn run start
ターミナルには Hello from Electron 👋
と出力されるはずです。 おめでとうございます、これにより Electron で初めてコードを 1 行実行しました! 次に、HTML でユーザーインターフェースを作成し、それをネイティブウインドウへ読み込む方法を学びます。
ウェブページを BrowserWindow で読み込む
Electron では、各ウインドウにウェブページが表示され、これはローカルの HTML ファイルまたはリモートのウェブアドレスから読み込むことができます。 このサンプルでは、ローカルファイルを読み込んでみましょう。 まず、プロジェクトのルートフォルダに index.html
ファイルを作成し、以下の基本的なウェブページを作成することから始めます。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
</body>
</html>
Now that you have a web page, you can load it into an Electron BrowserWindow. main.js
ファイルの内容を以下のコードに置き換えてください。 ハイライトしたブロックをそれぞれ別々に解説します。
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
モジュールのインポート
const { app, BrowserWindow } = require('electron')
1 行目では、CommonJS のモジュール構文で 2 つの Electron モジュールをインポートしています。
- app, which controls your application's event lifecycle.
- BrowserWindow, which creates and manages app windows.
モジュールの大文字小文字規約
app モジュールと BrowserWindow モジュールの大文字小文字の規則の違いにお気づきでしょうか。 ここでは Electron は典型的な JavaScript の慣習に従っています。PascalCase のモジュールはインスタンス化可能なクラスコンストラクタ (例: BrowserWindow、Tray、Notification) であるのに対し、camelCase のモジュールはインスタンス化できません (例: app、ipcRenderer、webContents)。
型付きの import エイリアス
TypeScript コードを記述する際の型検査を改善するために、electron/main
からメインプロセスのモジュールをインポートする選択ができます。
const { app, BrowserWindow } = require('electron/main')
For more information, see the Process Model docs.
Electron 28 から、Electron での ECMAScript Modules (例えば import
によるモジュールの読み込み) がサポートされています。 Electron での ESM の状態についてさらなる情報は、私たちの ESM のガイド にあります。
ウインドウを作成する再使用可能な関数を書く
この createWindow()
関数は、ウェブページを新しい BrowserWindow インスタンスで読み込みます。
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
アプリの準備ができたら関数を呼び出す
app.whenReady().then(() => {
createWindow()
})
Electron のコアモジュールの多くは Node.js の EventEmitter で、Node の非同期の イベント駆動型アーキテクチャに準拠しています。 app モジュールはこれらエミッターのうちの 1 つです。
In Electron, BrowserWindows can only be created after the app module's ready
event is fired. You can wait for this event by using the app.whenReady()
API and calling createWindow()
once its promise is fulfilled.
Node.js のイベントは通常、エミッタの .on
関数を用いてリッスンします。
+ app.on('ready', () => {
- app.whenReady().then(() => {
createWindow()
})
しかし, Electron は ready
イベントのヘルパーとして app.whenReady()
を公開しています。これは直接リッスンすることによる些細なミスを回避するためのものです。 詳細は electron/electron#21972 をご参照ください。
この時点で、Electron アプリケーションの start
コマンドを実行すると、ウェブページを表示するウインドウが正常に開くでしょう。
アプリがウインドウに表示する各ウェブページは、レンダラー プロセスという (または単に レンダラー と略す) 個別のプロセスで実行されます。 レンダラープロセスは典型的なフロントエンドのウェブ開発と同じように JavaScript の API へアクセスでき、同じツール、例えば webpack によるコードのバンドルと Minify、React によるユーザーインターフェイスの構築などが利用できます。
アプリのウインドウのライフサイクル管理
アプリケーションウインドウは、オペレーティングシステムによって動作が異なります。 Electron はそれぞれの慣習をデフォルトでは強制せず、慣習に従いたい場合はアプリのコードで実装する選択肢を提供します。 app モジュールと BrowserWindow モジュールが発生するイベントをリッスンすることで、基本的なウインドウの慣習的動作を実装できます。
Node の process.platform
変数を確認することで、特定プラットフォームの条件下でコードを実行できます。 注意として、取りうるプラットフォームの値は Electron が実行できる win32
(Windows)、linux
(Linux)、darwin
(macOS) の 3 つのみです。
全ウインドウを閉じた時にアプリを終了する (Windows & Linux)
一般的に Windows や Linux では、すべてのウインドウを閉じるとアプリケーションが完全に終了します。 To implement this pattern in your Electron app, listen for the app module's window-all-closed
event, and call app.quit()
to exit your app if the user is not on macOS.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
開いたウインドウがない場合にウインドウを開く (macOS)
一方、macOS アプリは一般的に、ウインドウを開いていなくても動作し続けます。 ウインドウがないときにアプリをアクティブにすると、新規ウインドウが開かれるでしょう。
To implement this feature, listen for the app module's activate
event, and call your existing createWindow()
method if no BrowserWindows are open.
ready
イベントの前ではウインドウを作成できないので、アプリが初期化された後に activate
イベントだけをリッスンする必要があります。 これは既存の whenReady()
コールバック内で activate イベントをリッスンすることでのみ実現できます。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
最終的なのスターターコード
- main.js
- index.html
const { app, BrowserWindow } = require('electron/main')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
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()
}
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
<p id="info"></p>
</body>
<script src="./renderer.js"></script>
</html>
任意: VS Code からのデバッグ
VS Code を使用してアプリケーションをデバッグしたい場合、VS Code をメインプロセスとレンダラープロセスの両方にアタッチする必要があります。 こちらは実行するためのサンプル構成です。 プロジェクトのフォルダ内に新しく .vscode
フォルダを作成し、その中に以下の launch.json を作成してください。
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
サイドバーから「実行とデバッグ」を選択すると「Main + renderer」オプションが表示され、メインとレンダラーの両方のプロセスでブレークポイントの設定やすべての変数の検査などができるようになります。
この launch.json
ファイルでは、以下 3 つの構成を作成しています。
Main
はメインプロセスを起動するもので、ポート 9222 をリモートデバッグのために公開します (--remote-debugging-port=9222
)。 これはRenderer
にアタッチするために使用するデバッガのポートです。 メインプロセスは Node.js プロセスであるため、タイプはnode
に設定します。Renderer
レンダラープロセスをデバッグするものです。 メインプロセスはレンダラープロセスを作成するものなので、新しいプロセスを作成する代わりにそれへと「アタッチ」("request": "attach"
) する必要があります。 レンダラープロセスはウェブのプロセスなので、使用するデバッガはchrome
となります。Main + renderer
は 複合タスク で、先程の構成すべてを同時に実行します。
Renderer
でプロセスにアタッチしているため、コードの最初の行が実行される前にデバッガーが接続しようとすると、早すぎてスキップされることがあります。 これは開発モードでコードを実行する前に、ページを更新したりタイムアウトを設定することで回避できます。
デバッグ分野をより深く掘り下げたい場合は、以下のガイドに詳しい情報が掲載されています。
概要
Electron アプリケーションは、npm パッケージを使用してセットアップされます。 Electron の実行形式はプロジェクトの devDependencies
にインストールされている必要があり、package.json ファイル内のスクリプトを用いて開発モードで実行できます。
この実行形式は package.json の main
プロパティにある JavaScript のエントリポイントを実行します。 このファイルは Electron の メインプロセス を制御します。メインプロセスは Node.js のインスタンスを実行し、アプリのライフサイクル、ネイティブインターフェースの表示、特権操作、レンダラープロセスの管理を担います。
レンダラープロセス (または略してレンダラー) はグラフィカルなコンテンツの表示を担います。 レンダラーにウェブページを読み込むには、ウェブアドレスまたはローカルの HTML ファイルを指定します。 レンダラーの動作は通常のウェブページと非常に似ており、同じウェブの API にアクセスできます。
次章のチュートリアルでは、レンダラープロセスを特権 API で拡張する方法と、プロセス間の通信方法について学習します。