※本記事は個人の自己研鑽として取り組んだ内容であり、所属組織の公式見解や業務事例ではありません。
概要
- 日頃、Javaに触れている筆者が、Electronでアプリを作成する一連の学習で得た気づきを共有できたらと考えています...
- 筆者の理解不足、環境やバージョンにより挙動が変わる場合などがあり得るかもしれません。併せて公式情報もご確認ください...
前提・背景
-
Java:ある程度読み書きできます...
-
JavaScriptは普段はあまり関わらないです (推測や調べつつ解読できる程度です...)。
-
現状の私のJavaScript言語仕様の世界観:
- イベントドリブンな言語。イベントをトリガとして非同期処理の実行が標準の機構ででき、画面の実装が柔軟にできる。
https://developer.mozilla.org/ja/docs/Learn_web_development/Core/Scripting/What_is_JavaScript
- ブラウザで動くので動作環境の敷居が低い。デバッガもChromeやEdgeなどブラウザ組み込みの開発者ツールが使える。
https://learn.microsoft.com/en-us/microsoft-edge/devtools/overview
- Javaはスタティックな型付け。一方でJavaScriptは動的型付け。
-
Node.js、Electronはキーワードを聞いたことがあるレベルです...
Node.jsとElectronは、結局Javaでいうところの何なのだろうか...
- イメージ重視で、以下の理解をしました。
- Node.js:実行環境。JavaでいうところのJVM + JRE (に似た立場)
ただし、Node.jsはChromeの中核なV8エンジンをブラウザ外で動かすもので、「実行環境」という立場のほかは、別物であると認識しました。
https://nodejs.org/en/learn/getting-started/introduction-to-nodejs#introduction-to-nodejs
- Electron:JavaでいうJavaFX(WebView) + 実行環境(Chromium + Node.js)を同梱して配布できるデスクトップアプリの基盤
ただし、JavaFXと仕組みは違って、Electronは、Chromium上でWeb技術で動いていると認識しました。
Electronで開発をするために何が必要なのだろうか...
- Node.jsを公式ページからインストールが必要でした。
https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
- Visual Studio Code (VS Code)で開発する場合、JavaScriptはシンタックスハイライトやデバッグが標準対応していて拡張機能なしでも可能と認識しました。
- Node.jsインストール後は、
node -vやnpm -vでインストールされたことを確認しました。
私の環境では、PowerShellで実行する場合、あらかじめ
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Processなどとし、コマンドを実行できるようにする必要がありました (もし実行する場合はセキュリティ的にご注意ください...)
Node.jsを入れた後、結局どうすればいいのだろうか
- コマンドをターミナルで実行することで、Electronのひな形プロジェクトを作ることができると分かりました。
- ひな形プロジェクトを作成した後は、当該フォルダをVS Codeで開き、開発に入れると認識しました。
An unhandled rejection has occurred inside Forge: Error: ENOENT: no such file or directory, scandir
- ひな形プロジェクト作成コマンドを実行しましたが上記エラーが発生しました。
-
npx create-electron-app@latest hello-electronで実行するとできない模様です。 -
npx create-electron-app@latest my-app --template=webpackというように、--templateを指定するとできました。
npm cache verifyをしてみましたが、変わりませんでした。
テンプレートでのwebpackやvite(ヴィート)は、ビルドツールのことを意味していて、webpackが安定している一方で、動作速度はviteが早い模様です。
ひな形プロジェクトはできたし、VS Codeで開いてみたけど、どうやってアプリ起動するのだろうか...
-
npm startコマンドをVS Codeのターミナルで実行すると起動しました
起動したひな形プロジェクトのアプリの右半分に開発者ツールが出ていて消したい or 間違えて閉じてしまったからもう一度表示したい...
- Electronでは、メニューバーを設定しなかった場合、デフォルトでアプリにメニューバーが表示されると認識しました。
https://www.electronjs.org/docs/latest/api/menu#menusetapplicationmenumenu
- 開発者ツールは、デフォルトのメニューバーでの
View->Toggle Developer Toolsで表示・非表示を切り替えられると認識しました。
Electronのプロジェクトにいろんなファイルがあるが、何がどうなっているのだろうか...
イメージとして、以下と認識しました。
-
index.html、index.css、renderer.js-> フロントエンド側の実装
https://www.electronjs.org/docs/latest/tutorial/process-model#the-renderer-process
-
main.js-> バックエンド側の実装
https://www.electronjs.org/docs/latest/tutorial/process-model#window-management
-
preload.js-> フロントエンド側からアクセス可能なバックエンド側APIの公開状況を定義する。
https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
JavaScriptにおける「関数」と「メソッド」って違いは何だろうか...ただの別名だろうか...
- 使い分けされていると認識しました。
- 関数:function や、アロー関数で宣言した処理のことを意味する。
- メソッド:関数のうち、「オブジェクトのプロパティにて参照を持っているもの」を意味する。
.js内での冒頭でJavaでいうimportのようなことをしているように見えるが、const {app, BrowserWindow, ipcMain} = require('electron'); はどういうことなのだろうか...
-
requireメソッドは、Node.jsが提供する「CommonJS」と呼ばれるJSモジュールの読み込む手段で、electronのモジュールを取り込んでいると認識しました。
https://www.electronjs.org/docs/latest/tutorial/tutorial-first-app#importing-modules
- 以下の2つは同義であると理解しました。
const {app, BrowserWindow, ipcMain} = require('electron');
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const ipcMain = electron.ipcMain;
- つまり、ロードしたモジュールから
{ }で列挙した名称のオブジェクトだけをimportしていると認識しました。この一連の仕組みを、「構造分解」と呼ぶことを認識しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring
戻り値で、return {キー: 値}; がどうしてこう書けるか分からない...
-
{ }は、オブジェクトを作る式と認識しました。この機構を「オブジェクト初期化子(Object initializer)」と呼ぶと認識しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Object_initializer
-
{ }の中に、プロパティ名と値のペアを列挙することでシンプルに書けるという点では、Javaでいうところのインスタンス初期化子を利用し任意の値が入ったMapを作るnew HashMap<>(){{put(key, value)}}に感覚は近いものの、あくまで作られるのはMapではなくオブジェクトであると認識しました。
const $ = (selection) => document.querySelector(selection);がどうしてこう書けるかわからない...
- JavaScriptでは、関数を値として扱うことができ、変数にも代入できると認識しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions
-
const $となっているため、代入先は名称$の変数と認識しました。 -
(selection) => document.querySelector(selection);が関数部分と認識しました。=>はアロー関数式と呼び、関数を定義できると認識しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions
- JavaでいうところのFunctional Interfaceのラムダ式を変数で持てるような状況に近いと解釈しました。
- 呼び出し側では
const list = $('#items')というように、$へ引数を渡せば処理結果が得られると認識しました。
JavaのFunctional Interfaceでは、
<<Functional Interfaceラムダを代入済みの変数>>.apply(<<引数>>)などというように、Functional Interfaceごとに用意されたメソッドのシグネチャで呼び出す必要があるので、ここは似ていないと認識しました。
画面のUIとしてbootstrapを使いたい。CDNでの読み込みではなくプロジェクトにファイルを配置して使いたい。bootstrapのcssやjs、独自に定義したcssを画面に反映したい。どうすればいいのか...
- 公式サイトからbootstrapのファイルを取得し、プロジェクト内に配置したうえで、以下を
renderer.js冒頭に記述することで、cssが反映され、変数bootstrap経由でbootstrapのメソッドが使えることを認識しました。
https://getbootstrap.com/docs/5.3/getting-started/javascript#using-bootstrap-as-a-module
https://getbootstrap.com/docs/5.0/getting-started/webpack#importing-compiled-css
import '<<相対パス>>/bootstrap.min.css'
import * as bootstrap from '<<相対パス>>/bootstrap.bundle.min.js'
import '<<相対パス>>/<<独自のcss>>.css'
Promiseって何? 非同期系の処理なのは推測した...
- 将来いつか確定する(成功/失敗)を枠組みとしてあらわしているオブジェクトと解釈しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise
-
thenメソッドやcatchメソッドで結果が実際に確定し渡ってきた後の処理を、メソッドチェーンとしてシンプルにかけたり、async/awaitキーワードを使って同期処理のような見た目で記述できると認識しました。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/await
フロントエンドから使いたいバックエンド処理はpreload.jsにて公開の設定を記述するのはわかったけど、どうやるのだろうか...
-
contextBridgeを使うと認識しました。
https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
-
contextBridge.exposeInMainWorldメソッドにて、ipcRenderer.invokeメソッドを使って定義を記述することで公開設定ができると認識しました。
https://www.electronjs.org/docs/latest/api/ipc-renderer#ipcrendererinvokechannel-args
-
renderer.js側からはwindow.api.<<公開API名>>で使用することができると認識しました。
https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
jsonファイルを永続化の手段として実装した。ただ、いざnpm startでアプリ起動してみたが、jsonファイルの実態はどこに作られているのだろうか...
- 作成場所を
app.getPath('userData')としていたので、<<ユーザーフォルダ>>\AppData\Roaming\<<アプリ名>>配下に作成されていました。適時エクスプローラで表示することで、実際に書き込まれている内容を確認しやすくなりました。
https://www.electronjs.org/docs/latest/api/app#appgetpathname
指定URLをブラウザで開く処理を入れたいんだが、どうやればいいのだろうか...
-
shell.openExternalメソッドにURLを渡すことで関連付けられたブラウザが開くと認識しました。
学習の過程で、ブックマークアプリを作成できました...
むすび
- ElectronはHTML + JavaScript + CSSのWeb技術を使って柔軟なアプリ開発ができると知り、様々なアプリで導入されている背景をうかがい知ることができました。
- 加えて最近ではLLMを使って、HTML + JavaScript + CSSを1つのHTMLにまとめた小さなアプリを素早く生成しプロトタイピングするという使い方もあり、日常でのJavaScriptやCSSを目にする機会を見据えて、今後も触れていきたいと考えています...
- 最後までお読みくださり、ありがとうございました!

