Electron은 메인 프로세스와 렌더러 프로세스로 나뉘어 동작하며, 각각의 역할과 권한이 다릅니다.
메인 프로세스는 Node.js와 OS에 접근할 수 있지만, 렌더러 프로세스는 기본적으로 보안상의 이유로 이런 권한이 제한됩니다.
preload 스크립트를 이 두 프로세스 간의 안전한 연결을 가능하게 해주는 핵심 도구입니다.
Preload 스크립트의 역할
Preload 스크립트는 렌더러 프로세스가 HTML을 로드하기 전에 실행되는 JavaScript 파일입니다. 이 스크립트는 Node.js와 Electron API에 제한적으로 접근할 수 있으며, 렌더러와 메인 간의 안전한 다리 역할을 합니다.
- 보안 강화: 렌더러에 전체 Node.js 환경을 노출하지 않고, 필요한 기능만 선택적으로 제공합니다.
- API 중개: contextBridge를 사용해 메인 프로세스의 데이터를 렌더러에 전달하거나, IPC를 통해 통신을 중재합니다.
Preload 스크립트로 API 노출하기
Electron의 process.versions 정보를 렌더러에 노출하고, 메인 프로세스로부터 "ping" 요청에 대한 응답을 받아오는 기능을 구현해 보겠습니다. 여기서 제공하는 API는 전역 객체 window.electronAPI를 통해 접근할 수 있도록 합니다.
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
// 버전 정보를 한 번에 반환하는 함수
getVersions: () => ({
node: process.versions.node,
chrome: process.versions.chrome,
electron: process.versions.electron
}),
// 메인 프로세스로 "ping" 메시지를 보내고 응답을 받는 함수
pingServer: async () => await ipcRenderer.invoke('ping-server')
});
- contextBridge.exposeInMainWorld를 사용해 window.electronAPI 객체를 생성합니다.
- getVersions() 함수는 Electron, Node, Chrome의 버전을 한 번에 객체 형태로 반환합니다.
- pingServer() 함수는 IPC 채널 ping-server를 통해 메인 프로세스에 메시지를 보내고, 응답을 비동기로 받아옵니다.
메인 프로세스에서 IPC 핸들러 설정하기
메인 프로세스에서는 preload 스크립트에서 호출한 IPC 요청을 처리할 수 있도록 핸들러를 등록해야 합니다.
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
function createAppWindow() {
const win = new BrowserWindow({
width: 900,
height: 700,
webPreferences: {
preload: path.join(__dirname, 'preload.js'), // preload 스크립트 경로 설정
contextIsolation: true, // 보안을 위해 활성화
nodeIntegration: false // 렌더러에서 Node.js 접근 차단
}
});
win.loadFile('index.html');
}
app.whenReady().then(() => {
// IPC 핸들러 등록: 'ping-server' 채널로 요청이 들어오면 'pong from main process'를 응답
ipcMain.handle('ping-server', () => {
return 'pong from main process';
});
createAppWindow();
// macOS: 앱이 활성화되었을 때 열린 창이 없으면 새 창 생성
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createAppWindow();
});
});
// Windows, Linux: 모든 창이 닫히면 앱 종료
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
});
렌더러 프로세스에서 전역 API와 IPC 호출 사용하기
이제 렌더러에서 preload 스크립트로 노출된 API를 사용하여 버전 정보를 표시하고, 메인 프로세스로 "ping" 요청을 보내 응답을 출력해봅니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Electron Preload 데모</title>
</head>
<body>
<h1>Electron Preload 스크립트 예제</h1>
<p id="version-info">버전 정보를 불러오는 중...</p>
<p id="ping-result">Ping 응답을 기다리는 중...</p>
<script src="renderer.js"></script>
</body>
</html>
// renderer.js
(async () => {
// preload 스크립트에서 노출한 electronAPI를 사용하여 버전 정보 가져오기
const versions = window.electronAPI.getVersions();
const versionInfo = `Node: ${versions.node}, Chrome: ${versions.chrome}, Electron: ${versions.electron}`;
document.getElementById('version-info').innerText = versionInfo;
// 메인 프로세스로 ping 메시지 전송 및 응답 처리
const response = await window.electronAPI.pingServer();
document.getElementById('ping-result').innerText = `Ping 응답: ${response}`;
})();
'Electron' 카테고리의 다른 글
[Electron] 튜토리얼 Part 5: 앱 패키징 및 배포하기 (0) | 2025.03.20 |
---|---|
[Electron] 튜토리얼 Part 4: 기능 확장 (0) | 2025.03.20 |
[Electron] 튜토리얼 Part 2: 첫 데스크탑 앱 만들기 (0) | 2025.03.19 |
[Electron] 튜토리얼 Part 1: 시작하기 전 알아야 할 모든 것 (0) | 2025.03.19 |
[Electron] 일렉트론이란 무엇인가 (0) | 2025.03.19 |