초기 설정 이후 본격적으로 Electron 코드를 작성하기 전에 Electron의 생명주기에 대해 알아보자.
Electron에서 제공하는 app 객체는 Electron의 생명주기를 관리한다.
app 객체를 통해 앱의 라이프 사이클 관련 신호를 받을 수 있다.
app.on('EVENT', ()=>{})
식으로 받는다.
app의 준비가 완료 됐을때 이를 감지할 수 있는 방법은
app.on('ready', ()=>{})
app.on('will-finish-launching', ()=>{})
app.whenReady()
가 있다.
app.on('ready', ()=>{})
는 MAC OS에서 넘겨주는 launchInfo가 필요할 경우 사용한다. launchInfo에는 유저 정보가 담겨있다.
will-finish-launching
는 Window와 Linux에서 launchInfo가 필요한 경우 사용한다.
app.whenReady()
는 프로미스를 리턴하여 동기화 처리를할 수 있게 만들어준다.
window들이 닫히기 시작할 때 발생하는 이벤트이다.
넘겨받는 e객체를 이용하여 e.preventDefault() 호출하면 앱이 종료되는 것을 막을 수 있다.
window들이 모두 닫혔을 때 발생하는 이벤트이다.
단, app.quit()이 호출되거나 유저가 Cmd + Q
를 입력한 경우 발생하지 않는다.
window들은 이미 모두 닫혔고, 앱이 종료되기 전 발생하는 이벤트이다.
넘겨받는 e객체를 이용하여 e.preventDefault() 호출하면 앱이 종료되는 것을 막을 수 있다.
앱이 종료될 때 발생하는 이벤트이다.
생명주기를 어느정도 알아보았으니 이제 코드를 작성해 보자.
import Electron from 'electron';
import { app, Menu, BrowserWindow, ipcMain } from 'electron';
const APP_WIDTH = 570;
const APP_HEIGHT = isMac ? 570 : 600;
const isMac = process.platform === 'darwin';
function createWindow() {
const win = new BrowserWindow({
width: APP_WIDTH,
height: APP_HEIGHT,
webPreferences: {
nodeIntegration: true,
},
resizable: false,
});
win.loadFile('src/renderer/index.html');
return win;
}
// app 시작
app
.whenReady() // 앱이 준비되면
.then(createWindow) // 윈도우 만들기
.then((window: Electron.BrowserWindow) => {
// 메뉴 만들기
Menu.setApplicationMenu(
Menu.buildFromTemplate([
...(isMac ? [{ label: app.name }] : []),
{
label: 'File',
submenu: [
{
label: 'logger',
click: () => {
//여기에 logger 메뉴를 클릭시 실행할 함수를 넣는다. ex) window.webContents.send(IPC.OPEN_LOGGER, 'open');
},
},
],
},
]),
);
});
// Mac의 경우 종료를 해도 최소화 상태가 된 것처럼 만들 수 있다.
// Mac에서 종료 버튼으로 앱을 죽이지 않고 살려두려면 app.quit으로 죽이지 않고 activate 이벤트가 발생 했을때 윈도우만 새로 만든다
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
app이 준비되면 createWindow
를 이용하여 윈도우를 만드는 간단한 로직이다.
메뉴의 경우 Menu.setApplicationMenu
와 Menu.buildFromTemplate
을 통해 생성한다.
메뉴를 만들때 Mac OS의 경우 아무리 app.name을 작성해도 Electron으로 보이는 경우가 있다.
이는 인스톨 파일로 배포할 때 정상적으로 app.name값이 들어가므로 걱정하지 말자.
이제 Renderer Process를 작성하면 끝난다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link rel="stylesheet" href="./Styles/normalize.css"/>
<script>if (typeof module === 'object') {
window.module = module; module = undefined;
}
</script>
<script>if (window.module) module = window.module;</script>
<script defer src="./dist/index-bundle.js"></script>
</head>
<body style="background: white;">
<div id="root"></div>
<aside id="modal"></aside>
</body>
</html>
Renderer Process의 경우 일반적인 Front-End 코드를 작성한다고 생각하면 된다.
index.html을 작성하고 Renderer Process 역할을 할 js 파일(ts에서 js로 변환된 index.js)를 import하면 된다.
React처럼 js가 dom을 생성하도록 만들기 위해 root와 modal을 제외한 어떠한 마크업도 남기지 않았지만 꼭 이런 방식으로 작성할 필요는 없다.