Electronとはクロスプラットフォームでディスクトップアプリをweb(html,css,js)開発技術で作れるフレームワークだそうです。(公式)
ChromiumとNode.js上に乗っていて思ったよりは軽量に動作しました。
使い方を理解すると簡単でしたが、動かすまでに躓いたところが多かったので私のやり方をシェアします。
テスト環境
Windows : 10
Node.js : v20.11.0
Electron v28.2.1
インストール
- Node.jsのインストール:公式からダウンロード
- Electronのインストール
- コマンドプロンプトで下記を実行
npm i electron -g
electron -v #for check install version
使い方1:ブラウザ表示
Electronは2つの処理系に分かれていて、それぞれメインプロセスとレンダラープロセスと呼んでいます。
- メインプロセス:Node.jsの機能を使ったりブラウザの設定をしたりするプロセスでjavascriptでコードを書きます。
- レンダラープロセス:表示する為のプロセスで要するにwebページを作ります。
よって簡単に組み立てるならメインプロセスのjsファイルとレンダラープロセス(Chromiumで表示させる)htmlファイルの2つあれば完成です。
メインプロセスのファイル名を仮にmain.jsとします。
- index.jsとしている例が多いですが名前はどうでもいいです
- 読み込むhtmlファイルは今回はindex.htmlとしてmain.jsと同じ階層に置いています
const {app, BrowserWindow} = require('electron');
app.on('ready', () => {
mainWindow = new BrowserWindow({});
// set index.html path
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.on('closed', function() {
mainWindow = null;
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>electron sample</title>
</head>
<body>
</body>
</html>
上記の2ファイルを作成したらElectronをコマンドプロンプトから下記のコマンドで実行します。
electron main.js
何も描画されてないブラウザが表示されていれば完成です。
使い方2:ブラウザの表示設定を弄る
ブラウザの設定を色々弄ってみます。
全画面化して描画の無い箇所は透明に、常に一番上に表示させてみます。
マウスイベントも無視するように設定しました。
透明化したのでhtmlがちゃんと描画されているかどうか確認する為にindex.htmlの方はpタグで確認用の文字列を足しました。
const {app, BrowserWindow, screen} = require('electron');
app.on('ready', () => {
var size = screen.getPrimaryDisplay().size;
mainWindow = new BrowserWindow({
width: size.width,
height: size.height,
frame: false,
show: true,
transparent: true,
resizable: false,
'always-on-top': true,
});
mainWindow.setIgnoreMouseEvents(true);
// set index.html path
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.on('closed', function() {
mainWindow = null;
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>electron sample</title>
</head>
<body>
<p>test</p>
</body>
</html>
使い方1と同じく”electron main.js”で設定通りブラウザが動いていれば完成です。
使い方3:デバッグしたい、警告を消したい
Chromeブラウザの検証を押すと出てくるDevToolsの表示をさせます。
DevToolsを表示させると透明化のパラメータが無効になります。(transparent)
また、DevToolsのコンソールに出てくる警告「Electron Security Warning (Node.js Integration with Remote Content)~」はパッケージ化すると消えますが、してない段階では消えないので見やすさの為に一旦消しておきます。
上記の修正をmain.jsに織り込むと下記の様になります。
const {app, BrowserWindow, screen} = require('electron');
// ignore security warning
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = '1';
app.on('ready', () => {
var size = screen.getPrimaryDisplay().size;
mainWindow = new BrowserWindow({
width: size.width,
height: size.height,
frame: false,
show: true,
transparent: true,
resizable: false,
'always-on-top': true,
});
mainWindow.setIgnoreMouseEvents(true);
// set index.html path
mainWindow.loadURL('file://' + __dirname + '/index.html');
// show devtools
mainWindow.webContents.openDevTools();
mainWindow.on('closed', function() {
mainWindow = null;
});
});
index.htmlはそのままで、electron main.jsのコマンドでDevToolsが表示されていてwarningが消えていれば成功。
使い方4:preload scriptを実装する
レンダラープロセス側(htmlで読み込んだjavascript等)でファイルを読み込んだりディレクトリを検索したりとNode.jsの機能を使いたい場合があります。
Electronではレンダラープロセスからメインプロセスの関数を叩きたい場合icpというプロセス間通信を使って実現出来ます。
ところが、直接通信をやりとりするとセキュリティ上のリスクがあるのでレンダラープロセスへ公開APIのようなものを用意して実装するとセキュリティ上安全に情報のやり取りを行えます。
その公開APIが要するにpreload scriptです。
よってファイルが1つ増えて下記の3つを用意します。
- main.js | ブラウザの動作や表示を設定。Node.jsの機能も使い放題
- index.html(&javascript,css) | ブラウザに表示させる内容
- preload.js | index.htmlからmain.jsの関数を使ってNode.jsの機能などを利用
先ずはmain.jsを下記の用に実装します。
const {app, BrowserWindow, ipcMain} = require('electron');
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = '1';
function getDirname() {
return __dirname;
}
app.on('ready', () => {
var preloadPath = __dirname +'/preload.js';
mainWindow = new BrowserWindow({
webPreferences: {
preload: preloadPath
}
});
// set index.html path
mainWindow.loadURL('file://' + __dirname + '/index.html');
mainWindow.on('closed', function() {
mainWindow = null;
});
// set channel handler
ipcMain.handle('util', getDirname);
});
__dirnameというNode.jsで用意されているプロジェクトのディレクトリパスを返す関数を用意しました。
次にpreload.jsでgetDirnameを公開します。
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
getDirname: () => ipcRenderer.invoke('util')
});
最後にindex.htmlのscript内でgetDirnameを叩いてみます。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>electron sample</title>
</head>
<body>
<script>
async function sample(){
const __dirname = await window.electronAPI.getDirname();
console.log(__dirname);
}
sample();
</script>
</body>
</html>
DevToolsのコンソールにディレクトリのパスが表示されたら成功