Elecron으로 만든 Application은 하나의 웹 사이트가 실행 가능한 프로그램으로 작동한다고 생각해도 좋습니다.
프로그램의 덩치가 커지면 여러 페이지를 제어해야 할 필요가 생깁니다.
우아하게 떠있는 백조가 사실은 가라앉지 않기 위해 발을 구르고 있는 것처럼,
우아한 프로그램을 위해 보이지 않는 곳에서 발을 구르는 법을 알아봅니다.
2개의 창
지난 번에는 하나의 창만 표시했었습니다.
당연한 이야기지만 여러 창을 표시하는 것도 가능합니다.
이번 예제에서는 아래 동영상처럼 서로 다른 창이 통신하는 프로그램을 작성해봅니다.
ipcMain, ipcRenderer
Electron은 메인 프로세스와 렌더러 프로세스, 쉽게 말해서 Node.js 영역과 웹 페이지 영역이 통신할 수 있는 방법으로
ipcMain과 ipcRenderer를 제공합니다.
ipcMain은 메인 프로세스에서 렌더러 프로세스로 통신할 때,
ipcRenderer는 렌더러 프로세스에서 메인 프로세스로 통신할 때 사용합니다.
사용법은 아래 코드 수정 단락에서 확인할 수 있습니다.
코드 수정
지난 예제의 디렉토리 구조입니다.
main.js
파일과 index.html
파일을 아래와 같이 수정합니다.
index.html
<!DOCTYPE html>
<html>
<head>
<title>사과 가져오기</title>
</head>
<body>
<p>
<button id="btnCount">사과 갯수 확인하기</button>
<button id="btnSteal">사과 가져오기</button>
<button id="btnBroadcast">갯수 알리기</button>
</p>
<p>
남은 사과는 <span id="txtCount"></span>개 입니다.
</p>
<script>
const electron = require('electron');
const print = (num = 10) => document.getElementById('txtCount').innerText = num;
document.getElementById('btnCount').onclick = () => electron.ipcRenderer.send('reqCount');
document.getElementById('btnSteal').onclick = () => electron.ipcRenderer.send('reqSteal');
document.getElementById('btnBroadcast').onclick = () => electron.ipcRenderer.send('reqBroadcast');
electron.ipcRenderer.on('count', (e, count) => print(count));
print();
</script>
</body>
</html>
21~23번째 줄: 버튼을 누르면 메인 프로세스로 각각의 신호를 보냅니다.
25번째 줄: 메인프로세스로부터 count
신호가 수신되면 수신된 갯수 데이터를 출력합니다.
main.js
const { app, BrowserWindow, ipcMain, webContents } = require('electron');
const path = require('path');
const createWindow = () => {
const options = {
width: 320,
height: 240,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false,
}
};
const first = new BrowserWindow(options);
const second = new BrowserWindow(options);
first.loadFile('index.html');
second.loadFile('index.html');
};
app.whenReady().then(() => {
createWindow();
let apples = 10;
ipcMain.on('reqCount', (e) => {
e.reply('count', apples);
});
ipcMain.on('reqSteal', (e) => {
apples--;
e.reply('count', apples);
});
ipcMain.on('reqBroadcast', (e) => {
const contents = webContents.getAllWebContents();
for (const c of contents) c.send('count', apples);
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
14~15번째 줄: 동일한 옵션으로 2개의 창을 만듭니다.
24번째 줄: 남은 사과 갯수를 정의합니다. 공유되어야 하는 데이터는 메인 프로세스가 가지고 있습니다.
26~32번째 줄: 각각의 신호가 수신되면 남은 사과의 갯수를 응답합니다. 응답하는 경우 매개변수로 전달된 event
객체에 reply
함수를 호출하여 데이터를 전달합니다.
33~36번째 줄: 모두에게 사과 갯수를 알리기로 했다면 전체 창에 접근해야 합니다. event
객체는 요청한 창만 있기 때문에 다른 방법을 씁니다. webContents.getAllWebContents()
함수는 모든 WebContents
인스턴스의 배열을 반환합니다.
실행
터미널에 아래 명령어를 입력하면 App이 실행됩니다.
npm start
참고 문서
- Inter-Process Communication | Electron - https://www.electronjs.org/docs/latest/tutorial/ipc
- webContents | Electron - https://www.electronjs.org/docs/latest/api/web-contents
- [Electron] require is not defined 해결 방법 - https://bug41.tistory.com/83