[Electron] Electron+React+Typescriptでマルチウィンドウアプリの作成
2023-02-01
2023-02-01
Electron+React+Typescript でマルチウィンドウアプリを作成した際の知見をまとめました。
検証環境
- Windows 10 Pro 22H2
- Node.js v18.14.0
- Electron 22.2.0
Renderer Process 側の対応
HashRouter によるルーティング
react-router-domをインストールし、HashRouter
コンポーネントでルーティングを定義します。
npm install react-router-dom
App.tsx
import React from 'react';
import MainView from './MainView';
import SubView from './SubView';
import { HashRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<HashRouter>
<Routes>
<Route path='/' element={<MainView />} />
<Route path='sub' element={<SubView />} />
</Routes>
</HashRouter>
);
};
export default App;
Main Process 側の対応
URLの末尾に#/[Renderer ProcessのRouteコンポーネントに設定したパス]
を追加します。
下記のコードでは、アプリの起動時にウィンドウが重ならないように、BrowserWindow
のインスタンス作成時に、x
, y
プロパティにウィンドウの初期位置を設定しています。
parent
プロパティに別のBrowserWindow
を指定することで、ウィンドウに親子関係を持たせ、親ウィンドウが閉じたときに子ウィンドウも自動で閉じるようにすることもできます。
Main.tsx
...
mainWindow = new BrowserWindow({
width: 1024,
height: 728,
x: 0,
y: 0,
...
});
subWindow = new BrowserWindow({
width: 1024,
height: 728,
x: 1024,
y: 0,
parent: mainWindow,
...
});
if (app.isPackaged) {
mainWindow.loadURL(`file://${__dirname}/../index.html#/`);
subWindow.loadURL(`file://${__dirname}/../index.html#/sub`);
} else {
mainWindow.loadURL('http://localhost:3000/index.html#/');
subWindow.loadURL(`http://localhost:3000/index.html#/sub`);
}
...
Electron React Boilerplateを使用した場合
Electron React Boilerplateを使用してプロジェクトを作成した場合、src/main/util.ts
を修正する必要があります。
src/main/util.ts
import { URL } from 'url';
import path from 'path';
export function resolveHtmlPath(htmlFileName: string, hash: string = '') {// ハッシュの引数を追加
if (process.env.NODE_ENV === 'development') {
const port = process.env.PORT || 1212;
const url = new URL(`http://localhost:${port}`);
url.pathname = htmlFileName;
url.hash = hash;// 開発用のHTMLパスにハッシュを追加
return url.href;
}
return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}#${hash}`;// 本番用のHTMLパスにハッシュを追加
}
src/renderer/App.tsx
import { HashRouter, Routes, Route } from 'react-router-dom';
import icon from '../../assets/icon.svg';
import './App.css';
function MainWindow() {
return (
<div>
<div className="Hello">
<img width="200" alt="icon" src={icon} />
</div>
<h1>Main Window</h1>
</div>
);
}
function SubWindow() {
return (
<div>
<div className="Hello">
<img width="200" alt="icon" src={icon} />
</div>
<h1>Sub Window</h1>
</div>
);
}
export default function App() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<MainWindow />} />
<Route path="/sub" element={<SubWindow />} />
</Routes>
</HashRouter>
);
}
src/main/main.ts
...
mainWindow = new BrowserWindow({
width: 1024,
height: 728,
x: 0,
y: 0,
...
});
subWindow = new BrowserWindow({
width: 512,
height: 728,
x: 1024,
y: 0,
parent: mainWindow,
...
});
mainWindow.loadURL(resolveHtmlPath('index.html'));
subWindow.loadURL(resolveHtmlPath('index.html', '/sub'));
...