본문 바로가기
JavaScript/Electron

Electron 핵심 프로세스 - 렌더러 프로세스

by curious week 2025. 3. 17.

렌더러 프로세스(Renderer Process)의 역할

렌더러 프로세스란?

렌더러 프로세스(Renderer Process)는 Electron에서 UI를 담당하는 프로세스입니다.
즉, 웹 기술(HTML, CSS, JavaScript)을 사용하여 화면을 렌더링하고 사용자 입력을 처리하는 역할을 합니다.

HTML, CSS, JavaScript를 사용하여 UI 구성
사용자 입력(클릭, 키보드 입력 등) 처리
렌더링된 웹페이지를 표시하고 이벤트 핸들링 수행
메인 프로세스와 IPC를 통해 통신 (데이터 요청, UI 업데이트 등)
React, Vue, Svelte 같은 프레임워크를 활용하여 UI 개발 가능

즉, 렌더러 프로세스는 Electron의 "웹 브라우저" 역할을 합니다!


1. 렌더러 프로세스의 주요 역할

1️⃣ UI 렌더링 HTML, CSS, JavaScript를 사용하여 화면 표시
2️⃣ 사용자 입력 처리 버튼 클릭, 키보드 입력 등의 이벤트 감지
3️⃣ 메인 프로세스와 통신 (IPC) 데이터를 주고받고 명령을 실행
4️⃣ 웹 API 및 프론트엔드 로직 처리 AJAX 요청, 로컬 스토리지 활용 등
5️⃣ 프레임워크 활용 가능 React, Vue, Svelte 같은 프레임워크와 결합 가능

렌더러 프로세스는 "웹 브라우저 탭"과 유사하며, 사용자 인터페이스를 처리하는 역할을 합니다.


렌더러 프로세스는 브라우저와 같은 환경에서 실행

렌더러 프로세스는 어떻게 실행될까?

Electron의 렌더러 프로세스(Renderer Process)는 웹 브라우저의 탭(Tab)과 유사한 환경에서 실행됩니다.
즉, 웹 기술(HTML, CSS, JavaScript)을 사용하여 UI를 렌더링하고, 일반적인 브라우저와 거의 동일한 환경을 제공합니다.

HTML, CSS, JavaScript를 사용하여 UI를 구성 가능
웹 브라우저처럼 DOM(Document Object Model) 조작 가능
window, document, localStorage 등 웹 API 사용 가능
크롬(Chrome) 기반의 렌더링 엔진(Blink) 사용
React, Vue, Svelte 같은 웹 프레임워크 사용 가능

즉, 렌더러 프로세스는 웹 브라우저처럼 실행되지만, Electron의 기능을 추가로 활용할 수 있습니다!


1. 렌더러 프로세스의 실행 방식

렌더러 프로세스는 BrowserWindow가 생성될 때 실행됩니다.

메인 프로세스에서 렌더러 프로세스를 실행하는 코드 (main.js)

const { app, BrowserWindow } = require("electron");

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: __dirname + "/preload.js", // 보안 강화를 위한 preload 설정
    }
  });

  mainWindow.loadFile("index.html"); // 렌더러 프로세스 실행 (HTML 파일 로드)
});

이제 index.html이 실행되며, 브라우저와 같은 환경이 만들어집니다.


2. 브라우저와 동일한 환경 제공

렌더러 프로세스는 웹 브라우저에서 실행하는 웹사이트와 거의 동일한 환경을 제공합니다.

렌더러 프로세스에서 실행 가능한 웹 API 예제 (index.html + index.js)

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Electron 렌더러 프로세스</title>
</head>
<body>
  <h1>렌더러 프로세스 환경</h1>
  <button id="checkBrowser">브라우저 정보 확인</button>
  <script src="index.js"></script>
</body>
</html>

index.js에서 웹 API 사용 예제

document.getElementById("checkBrowser").addEventListener("click", () => {
  alert("User Agent: " + navigator.userAgent);
});

이제 "브라우저 정보 확인" 버튼을 클릭하면 navigator.userAgent를 통해 브라우저 정보를 확인할 수 있습니다.


3. 렌더러 프로세스에서 사용할 수 있는 웹 API

렌더러 프로세스에서는 웹 브라우저에서 사용 가능한 모든 웹 API를 사용할 수 있습니다.

document HTML 문서(DOM)를 조작 가능
window 창 크기 조절, 이벤트 처리 가능
localStorage 로컬 데이터 저장 가능
fetch() HTTP 요청 가능 (AJAX)
navigator 사용자 정보, 네트워크 상태 확인 가능
console 디버깅 로그 출력 가능

웹 API (렌더러 프로세스에서 실행)

// 로컬 스토리지 사용
localStorage.setItem("username", "electron_user");
console.log("저장된 데이터:", localStorage.getItem("username"));

// HTTP 요청 보내기 (fetch API 사용)
fetch("https://jsonplaceholder.typicode.com/todos/1")
  .then(response => response.json())
  .then(data => console.log("받은 데이터:", data));

// 네트워크 상태 확인
console.log("온라인 상태:", navigator.onLine);

이제 렌더러 프로세스에서 브라우저처럼 localStorage, fetch, navigator를 사용할 수 있습니다.


4. 렌더러 프로세스와 일반 웹 브라우저의 차이점

렌더러 프로세스는 웹 브라우저와 거의 동일하지만, 몇 가지 차이점이 있습니다.  

  Electron 렌더러 프로세스 일반 웹 브라우저
Node.js API 사용 ❌ 기본적으로 불가능 (preload.js 필요) ❌ 사용 불가능
OS 네이티브 기능 ❌ 직접 사용 불가능 (ipcRenderer 필요) ❌ 사용 불가능
보안 설정 가능 ✅ contextIsolation, sandbox 사용 가능 ✅ 기본 보안 모델 적용
웹 API 지원 ✅ 대부분의 웹 API 지원 ✅ 완전한 웹 API 지원

즉, 렌더러 프로세스는 웹 브라우저와 거의 동일하지만, 보안상의 이유로 Node.js API를 직접 사용할 수 없습니다.


5. 렌더러 프로세스에서 Node.js API를 사용하려면?

렌더러 프로세스는 보안 문제로 인해 기본적으로 Node.js API를 사용할 수 없습니다.
그러나 preload.js를 사용하면 제한된 Node.js 기능을 사용할 수 있습니다.

preload.js에서 Node.js 기능 노출

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  sendMessage: (message) => ipcRenderer.send("messageToMain", message),
});

렌더러 프로세스에서 window.electronAPI 사용

document.getElementById("sendMessage").addEventListener("click", () => {
  window.electronAPI.sendMessage("버튼 클릭!");
});

이제 보안을 유지하면서 Node.js 기능을 제한적으로 사용할 수 있습니다.


6. React, Vue, Svelte 같은 프레임워크와 결합 가능

렌더러 프로세스는 일반적인 웹 환경과 동일하기 때문에, React, Vue 같은 프레임워크를 사용할 수 있습니다.

Electron + React

import { useEffect } from "react";

function App() {
  useEffect(() => {
    window.electronAPI.sendMessage("React에서 메시지 보냄!");
  }, []);

  return <button>클릭하세요</button>;
}

export default App;

React, Vue, Svelte 같은 웹 프레임워크를 그대로 사용할 수 있습니다.


7. 전체 코드 예제

main.js (메인 프로세스)

const { app, BrowserWindow } = require("electron");

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: __dirname + "/preload.js",
    }
  });

  mainWindow.loadFile("index.html");
});

preload.js (보안 설정)

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  sendMessage: (message) => ipcRenderer.send("messageToMain", message),
});

index.html + index.js (렌더러 프로세스)

<button id="checkBrowser">브라우저 정보 확인</button>
<script>
  document.getElementById("checkBrowser").addEventListener("click", () => {
    alert("User Agent: " + navigator.userAgent);
  });
</script>

이제 "브라우저 정보 확인" 버튼을 클릭하면 브라우저처럼 동작하는 것을 확인할 수 있습니다!


webPreferences 설정 (Node.js 활성화 여부 및 보안 설정)

webPreferences란?

Electron의 webPreferences는 렌더러 프로세스의 동작을 설정하는 옵션입니다.
특히, Node.js API를 활성화하거나 보안 설정을 조정할 때 사용됩니다.

Node.js API 활성화 (nodeIntegration)
보안 강화를 위한 contextIsolation
Preload 스크립트 설정 (preload)
렌더러 프로세스에서 파일 접근 제한 (sandbox)
CORS 정책 우회 (webSecurity)
개발자 도구 활성화 (devTools)

즉, webPreferences는 Electron 앱의 보안 및 기능을 결정하는 중요한 설정입니다!


1. webPreferences 기본 설정

Electron에서는 BrowserWindow를 생성할 때 webPreferences 옵션을 설정할 수 있습니다.

기본적인 BrowserWindow 설정

const { app, BrowserWindow } = require("electron");

app.whenReady().then(() => {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // Node.js API 기본적으로 비활성화
      contextIsolation: true, // 보안 강화
      preload: __dirname + "/preload.js", // 안전한 방식으로 Node.js API 제공
    }
  });

  mainWindow.loadFile("index.html");
});

이 설정은 보안을 고려한 기본적인 webPreferences 설정입니다. 
nodeIntegration: false를 설정하여 렌더러 프로세스에서 Node.js API를 차단합니다. 
Node.js API가 필요하면 preload.js를 통해 안전하게 제공해야 합니다. 


2. Node.js 활성화 여부 (nodeIntegration)

렌더러 프로세스에서 Node.js API를 사용할 수 있도록 설정할 수도 있습니다.

Node.js 활성화 (nodeIntegration: true) -> 보안 위험

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: true, // Node.js API 활성화 (보안 위험)
  }
});

렌더러 프로세스에서 require("fs") 같은 Node.js API를 직접 사용할 수 있습니다.
⚠️ 그러나 보안 위험이 크므로 추천되지 않습니다! (preload.js를 사용해야 함)


Node.js 비활성화 (nodeIntegration: false, 기본값)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: false, // Node.js API 비활성화 (보안 강화)
  }
});

렌더러 프로세스에서 Node.js API를 직접 사용할 수 없습니다. 
보안을 위해 기본적으로 false로 설정해야 합니다. 


3. 보안 강화 (contextIsolation)

렌더러 프로세스에서 Node.js API가 실행되지 않도록 보호하는 옵션입니다.

보안 강화를 위한 contextIsolation: true (권장)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    contextIsolation: true, // 렌더러 프로세스에서 Node.js API 격리
  }
});

contextIsolation: true를 설정하면 window 객체가 렌더러와 메인 프로세스에서 완전히 분리됩니다. 
이 설정을 사용하면 preload.js를 통해서만 Node.js API를 사용할 수 있습니다. 


4. Preload 스크립트 설정 (preload)

렌더러 프로세스에서 Node.js API를 안전하게 사용할 수 있도록 preload.js를 설정해야 합니다.

Preload 스크립트 설정 

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    preload: __dirname + "/preload.js", // 보안 강화를 위한 Preload 설정
  }
});

이제 preload.js를 사용하여 제한된 Node.js API를 제공할 수 있습니다. 

preload.js에서 안전한 API 제공

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  sendMessage: (message) => ipcRenderer.send("messageToMain", message),
});

렌더러 프로세스에서 window.electronAPI.sendMessage()를 통해 메인 프로세스와 통신할 수 있습니다. 


5. 파일 시스템 접근 제한 (sandbox)

렌더러 프로세스에서 파일 시스템에 접근할 수 없도록 제한할 수도 있습니다.

샌드박스 활성화 (sandbox: true)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    sandbox: true, // 파일 시스템 및 OS 접근 제한 (보안 강화)
  }
});

이제 렌더러 프로세스에서 파일 시스템을 직접 조작할 수 없습니다. 
Node.js API를 preload.js를 통해 안전하게 제공해야 합니다. 


6. CORS 정책 우회 (webSecurity)

일반적으로 웹 브라우저에서는 CORS 정책으로 인해 외부 도메인 요청이 차단될 수 있습니다.
이 경우, webSecurity: false를 설정하면 차단을 해제할 수 있습니다.

CORS 우회 (webSecurity: false)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    webSecurity: false, // CORS 정책 비활성화 (보안 위험)
  }
});

이제 모든 도메인에서 데이터를 요청할 수 있습니다. 
⚠️ 그러나 보안상 위험이 크므로 사용을 권장하지 않습니다.


7. 개발자 도구 활성화 (devTools)

기본적으로 devTools: true로 설정되어 있으며, 개발 중에는 활성화해 두는 것이 좋습니다.

개발자 도구 활성화 (devTools: true)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    devTools: true, // 개발자 도구 활성화 (기본값)
  }
});

이제 F12를 누르면 개발자 도구가 열립니다. 

배포 시 개발자 도구 비활성화 (devTools: false)

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    devTools: false, // 개발자 도구 비활성화 (배포용)
  }
});

배포 시에는 devTools: false로 설정하여 개발자 도구를 차단하는 것이 좋습니다. 


8. 전체 코드 예제

const { app, BrowserWindow } = require("electron");

app.whenReady().then(() => {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false, // Node.js API 비활성화 (보안)
      contextIsolation: true, // 보안 강화
      preload: __dirname + "/preload.js", // 안전한 방식으로 Node.js API 제공
      sandbox: true, // 파일 시스템 접근 제한
      webSecurity: true, // CORS 정책 활성화
      devTools: true, // 개발자 도구 활성화
    }
  });

  mainWindow.loadFile("index.html");
});

이제 보안을 유지하면서 Electron 앱을 실행할 수 있습니다. 


contextBridge를 이용한 안전한 통신 (보안 강화된 IPC)

contextBridge란?

Electron에서 **렌더러 프로세스(Renderer Process)**는 보안 문제로 인해 Node.js API를 직접 사용할 수 없습니다.
이를 해결하기 위해 preload.js에서 contextBridge를 이용하여 안전한 통신 방법을 제공합니다.

Node.js API를 안전하게 제공 (Node.js API 직접 사용 차단)
렌더러 프로세스에서 window 객체를 통해 API 호출 가능
XSS 공격 방지 (보안 강화를 위해 contextIsolation: true와 함께 사용)
메인 프로세스와 IPC(Inter-Process Communication) 통신 가능

즉, contextBridge를 활용하면 보안을 유지하면서도 메인 프로세스와 렌더러 프로세스 간의 안전한 통신이 가능합니다!


1. contextBridge를 이용한 기본적인 IPC 통신

1️⃣ main.js (메인 프로세스)

const { app, BrowserWindow, ipcMain } = require("electron");

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: __dirname + "/preload.js", // 보안 강화를 위한 Preload 설정
      contextIsolation: true, // 보안 강화
      nodeIntegration: false, // Node.js API 비활성화 (보안)
    }
  });

  mainWindow.loadFile("index.html");
});

// 렌더러 프로세스에서 메시지를 받음
ipcMain.on("messageToMain", (event, message) => {
  console.log("렌더러에서 받은 메시지:", message);
  event.reply("messageFromMain", "메인 프로세스에서 응답!");
});

렌더러 프로세스에서 받은 메시지를 출력하고, 응답을 보냅니다. 
보안을 위해 nodeIntegration: false, contextIsolation: true 설정을 사용합니다. 


2️⃣ preload.js (렌더러 프로세스에 안전한 API 제공)

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  sendMessage: (message) => ipcRenderer.send("messageToMain", message),
  receiveMessage: (callback) => ipcRenderer.on("messageFromMain", (event, data) => callback(data))
});

렌더러 프로세스에서 window.electronAPI.sendMessage()를 사용하여 메인 프로세스로 데이터를 보낼 수 있습니다. 
메인 프로세스에서 응답을 받을 때 window.electronAPI.receiveMessage()를 사용할 수 있습니다. 


3️⃣ index.html (렌더러 프로세스)

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Electron Secure IPC</title>
</head>
<body>
  <h1>Electron 안전한 IPC 통신</h1>
  <button id="sendMessage">메시지 보내기</button>
  <p id="responseMessage">응답 대기 중...</p>

  <script src="index.js"></script>
</body>
</html>

렌더러 프로세스 UI를 구성하는 HTML 파일입니다. 


4️⃣ index.js (렌더러 프로세스 이벤트 처리)

document.getElementById("sendMessage").addEventListener("click", () => {
  window.electronAPI.sendMessage("버튼이 클릭되었습니다!");
});

// 메인 프로세스에서 응답을 받음
window.electronAPI.receiveMessage((message) => {
  document.getElementById("responseMessage").textContent = "응답: " + message;
});

버튼 클릭 시 window.electronAPI.sendMessage()를 통해 메인 프로세스로 메시지를 전송합니다. 
메인 프로세스에서 응답을 받으면 window.electronAPI.receiveMessage()를 통해 화면에 출력합니다. 


2. contextBridge를 활용한 다양한 기능 제공

파일 시스템(fs)을 안전하게 노출하기

메인 프로세스에서 직접 fs 모듈을 사용할 수 있지만, 렌더러 프로세스에서는 보안상 직접 사용이 불가능합니다.
이를 preload.js를 통해 안전하게 제공할 수 있습니다.


1️⃣ preload.js에서 파일 읽기 기능 제공

const { contextBridge, ipcRenderer } = require("electron");

contextBridge.exposeInMainWorld("electronAPI", {
  readFile: (filePath) => ipcRenderer.invoke("readFile", filePath)
});

window.electronAPI.readFile(filePath)를 호출하면 메인 프로세스에 안전하게 요청할 수 있습니다. 


2️⃣ main.js에서 파일 읽기 처리

const { app, BrowserWindow, ipcMain } = require("electron");
const fs = require("fs");

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: __dirname + "/preload.js",
      contextIsolation: true,
      nodeIntegration: false,
    }
  });

  mainWindow.loadFile("index.html");
});

// 파일 읽기 요청 처리
ipcMain.handle("readFile", async (event, filePath) => {
  return fs.readFileSync(filePath, "utf8");
});

렌더러 프로세스에서 요청하면, 메인 프로세스에서 파일을 읽고 데이터를 반환합니다. 


3️⃣ index.js에서 파일 읽기 실행

document.getElementById("readButton").addEventListener("click", async () => {
  const content = await window.electronAPI.readFile("test.txt");
  console.log("파일 내용:", content);
});

이제 렌더러 프로세스에서 안전하게 파일 내용을 읽을 수 있습니다. 


3. 보안 강화를 위한 webPreferences 설정

렌더러 프로세스의 보안을 강화하려면 webPreferences를 적절히 설정해야 합니다.

보안 강화된 BrowserWindow 설정

const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nodeIntegration: false, // Node.js API 직접 접근 차단
    contextIsolation: true, // `window` 객체 격리
    enableRemoteModule: false, // `remote` 모듈 비활성화 (보안 강화)
    preload: __dirname + "/preload.js", // 안전한 API 제공
  }
});

보안을 강화하기 위해 nodeIntegration: false, contextIsolation: true를 사용해야 합니다. 
preload.js를 통해 필요한 기능만 안전하게 제공해야 합니다. 


4. 전체 코드 예제

main.js (메인 프로세스)

const { app, BrowserWindow, ipcMain } = require("electron");

let mainWindow;

app.whenReady().then(() => {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: __dirname + "/preload.js",
      contextIsolation: true,
      nodeIntegration: false,
    }
  });

  mainWindow.loadFile("index.html");
});

ipcMain.on("messageToMain", (event, message) => {
  console.log("렌더러에서 받은 메시지:", message);
  event.reply("messageFromMain", "메인 프로세스에서 응답!");
});

이제 보안을 유지하면서도 Electron에서 안전한 IPC 통신이 가능합니다.