定期的にAPIから取得したデータをチャート化してみたくなった。
node.jsだけでもいいけれど、electronで使いやすくしたい。
パッケージマネージャーはyarnを使いますがサンプル通りnpmでも問題ないです。
Electron 6.0.7
Electronとは
以前に若干触れましたがデスクトップアプリを作れるフレームワークです。
アプリ内でサーバ側処理とフロント側処理を書けます。
インストールと初期設定
まずはelectron本体とパッケージャーをインストール
1 2 3 4 |
mkdir project cd project yarn init yarn add --dev electron electron-packager |
package.jsonを適当に編集。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
"name": "electron-test", "version": "1.0.0", "license": "UNLICENSED", "author": "Narumium", "scripts": { "start": "electron ./src", "build:win": "electron-packager ./src app --platform=win32 --arch=x64 --overwrite" }, "devDependencies": { "electron": "^6.0.7", "electron-packager": "^14.0.5" } } |
srcフォルダを作ってその中にファイルを作っていきます。
index.html
とmain.js
、preload.js
を公式のクイックスタートからとってきます。
この中にもelectron実行用のpackage.jsonを作ります。
1 2 3 |
{ "main": "main.js" } |
ここまででファイル構成はこんな感じ。
現時点でrenderer.jsはないですが特に問題ないです。
yarn start
で起動、yarn build:win
でアプリビルドが出来ればOK。
メインプロセスとレンダラプロセスのやり取り
ipcMain
とipcRenderer
を使ってプロセス間の送受信をします。
ちなみに何も考えずにやるなら公式APIサンプル通りやるのが簡単。
まずメインプロセス(main.js
)を変更していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, "preload.js"), nodeIntegration: false, //ADD contextIsolation: true //ADD } }); ... mainWindow.webContents.openDevTools(); //ADD 開発者ツール用 } |
nodeIntegration
はレンダラプロセスでrequire()
を使うためにtrue
に(参考)。
が、セキュリティ的によくないというのも見かけてfalse
に。
次にcontextIsolation:false
にすることでwindow
オブジェクトを共通化してpreload.js
で設定する方法もしてみました。
1 2 |
const { ipcRenderer } = require("electron"); window.ipcRenderer = ipcRenderer; |
しかしこれもXSSの危険があるとかでtrue
にしました。
最終的にこんな感じに。
1 2 3 4 5 6 7 8 |
postMessage("test", "*"); onmessage = e => { switch (e.data) { case "reply": console.log("ipcRenderer reply"); break; } }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
... onmessage = e => { switch (e.data) { case "test": console.log("ipcRenderer send test"); ipcRenderer.send("test", "message"); break; } }; ipcRenderer.on("reply", (event, arg) => { console.log("ipcRenderer on reply:", arg); postMessage("reply", "*"); }); |
1 2 3 4 5 6 |
const { app, BrowserWindow, ipcMain } = require("electron"); ... ipcMain.on("test", (event, arg) => { console.log("ipcMain on test:", arg); event.reply("reply", "ok"); }); |
本当にこれでいいんだろうか。
以下のログが出ていれば成功です。
1 2 3 4 5 6 7 |
//Electron 開発者ツール ipcRenderer send test ipcRenderer on reply: ok ipcRenderer reply //ターミナル ipcMain on test: message |
ただこの例だと肝心のメッセージが送れていないので、postMessage
で送るのはJSONにしたりする必要がありそうです。
また上の例から漏れましたがメイン→プロセスの送信はBrowserWindowから。
1 |
mainWindow.webContents.send("reply", "main to renderer"); |
全体的なイメージはこんな感じ。
そもそも個人で使うならこんなセキュリティ気にする必要は全くないのですが、まぁそこは勉強をかねて。