はじめに
- Web(Nuxt.js)側のコードを独立して動かせる環境構築
- mainプロセスとrendererプロセス間の通信方法を検証
成果物
https://github.com/skysan87/nuxt-electron-sample
目次
プロジェクトの作成
- ElectronとNuxtを別のパッケージとして作成
- Monorepoだが、npmの
workspace
は利用していない- npmではnode_moduleが1つにまとめられてしまうため
- yarnの
nohoist
オプションはnpmになさそう
- Monorepoだが、npmの
- こちらの記事を参考に作成
ディレクトリ構成
. ├── electron │ ├── build ・・・electron-builderの出力フォルダ │ ├── dist ・・・nuxt generateの出力フォルダ │ ├── node_modules ・・・electronプロジェクトのモジュール │ ├── package.json │ └── src │ └── main ・・・mainプロセス群 │ └── web ├── (...) ・・・Nuxt.jsプロジェクト ├── node_modules ・・・Nuxt.jsプロジェクトのモジュール ├── nuxt.config.js └── package.json
作成手順
1. Nuxt.jsプロジェクト作成
- 既存プロジェクトの場合はwebフォルダ配下に移動
$ mkdir web && cd web # ここで設定は最小構成 $ npx create-nuxt-app . create-nuxt-app v3.6.0 ✨ Generating Nuxt.js project in . ? Project name: web ? Programming language: JavaScript ? Package manager: Npm ? UI framework: None ? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection) ? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection) ? Testing framework: None ? Rendering mode: Single Page App ? Deployment target: Static (Static/Jamstack hosting) ? Development tools: (Press <space> to select, <a> to toggle all, <i> to invert selection) ? What is your GitHub username? skysan ? Version control system: None
2. Electronプロジェクト作成
$ mkdir electron && cd electron $ npm init $ npm install -D electron electron-builder electron-devtools-installer
# srcディレクトリ配下 $ mkdir src & cd src # mainプロセス $ mkdir main
3. 出力先フォルダの設定
nuxt.config.js
- 環境ごとに出力先を変更
- electronでローカルファイル(HTML)を読み込む場合、nuxt generateでフォルダ(dist)をelectronフォルダ配下に出力するように指定
- 開発中はローカルサーバから画面を読み込む想定
generate: { dir: '../electron/dist' }
ElectronとNuxt.js間の通信
概要
- Mainプロセス(Electron)とRendererプロセス(Nuxt.js)間の通信はIPC通信
- contextBridgeを利用することで、Nuxt.js側はグローバルプロパティとしてメソッドをコールできる
- electronモジュールへの依存が低くなる
preload.js
- Renderer(Nuxt.js)との通信処理を記載
const { contextBridge, ipcRenderer} = require("electron") contextBridge.exposeInMainWorld( "api", { // renderer -> main -> renderer // rendererでのコール方法: "window.api.sendToMainWithResponse(args)" sendToMainWithResponse: async (args) => await ipcRenderer.invoke("ipc-send-to-main1", args), // renderer -> main // rendererでのコール方法: "window.api.sendToMain(args)" sendToMain: async (args) => ipcRenderer.send("ipc-send-to-main2", args), // main -> renderer // rendererでのコール方法: "window.api.recieveFromMain((arg) => { 処理 })" recieveFromMain: (listener) => { ipcRenderer.on("ipc-recieve-from-main", (event, args) => listener(args)) } } )
Rendererプロセス
// vueファイル export default { mounted () { // IPC通信(main -> renderer) window.api.recieveFromMain((args) => { console.log(args) }) }, methods: { async send () { // IPC通信(renderer -> main -> renderer) const result = await window.api.sendToMainWithResponse('1') console.log('response from main', result) }, send2 () { // IPC通信(renderer -> main) window.api.sendToMain('Hello World!') } } }
Mainプロセス
// IPC通信(renderer -> main -> renderer) // rendererプロセスからの通知を受信し、応答する ipcMain.handle('ipc-send-to-main1', async (ev, args) => { const result = await 何か処理(args) return result }) // IPC通信(renderer -> main) ipcMain.on('ipc-send-to-main2', (ev, args) => { console.log('renderer', args) }) setTimeout(() => { // IPC通信(main -> renderer) win.webContents.send("ipc-recieve-from-main", 'hello from main'); } , 10000)
実行ファイル作成(Macのみ記載)
- electron-builderで実行ファイルの作成
- electronのsrcフォルダと
nuxt generate
したdistフォルダをビルド対象
// electronのpackage.json "build": { "appId": "com.nuxt-electron-sample.app", "files": [ "dist", "src" ], "directories": { "output": "build", "app": "." }, "asar": true, "publish": null }
ビルドコマンド
// electronのpackage.json "build:mac": "electron-builder --mac --x64 --dir"
所感
以前Nuxt.jsとElectronを1つのパッケージにするとビルドエラーがしんどかった。 疎結合になったので、Web(Nuxt.js)とデスクトップアプリ(Electron)どちらも開発しやすくなった。