본문으로 건너뛰기
Previous
Next
Electron 완벽 가이드 | 크로스플랫폼 데스크톱 앱·IPC·Auto Update·실전 활용

Electron 완벽 가이드 | 크로스플랫폼 데스크톱 앱·IPC·Auto Update·실전 활용

Electron 완벽 가이드 | 크로스플랫폼 데스크톱 앱·IPC·Auto Update·실전 활용

이 글의 핵심

Electron 완벽 가이드에 대해 정리한 개발 블로그 글입니다. Electron으로 크로스플랫폼 데스크톱 앱을 개발하는 완벽 가이드입니다. Main/Renderer 프로세스, IPC, Auto Update, 배포까지 실전 예제로 정리했으며, Chromium·Node 통합,… 개념과 예제 코드를 단계적으로 다루며, 실무·학습에 참고할 수 있도록 구성했습니다. 관련 키워드:…

이 글의 핵심

Electron으로 크로스플랫폼 데스크톱 앱을 개발하는 완벽 가이드입니다. Main/Renderer 프로세스, IPC, Auto Update, 배포까지 실전 예제로 정리했으며, Chromium·Node 통합, IPC·컨텍스트 격리·네이티브 모듈, 프로덕션 운영 패턴까지 심화해 다룹니다.

실무 경험 공유: Electron으로 Windows, macOS, Linux 앱을 동시에 출시하면서, 개발 시간이 70% 단축되고 유지보수가 간편해진 경험을 공유합니다.

들어가며: “데스크톱 앱 개발이 어려워요”

실무 문제 시나리오

시나리오 1: 플랫폼마다 다시 개발해야 해요

Native 개발은 비용이 큽니다. Electron은 한 번 개발로 모든 플랫폼을 지원합니다. 시나리오 2: 웹 기술을 활용하고 싶어요

Native는 학습 곡선이 높습니다. Electron은 HTML, CSS, JavaScript를 사용합니다. 시나리오 3: 빠른 프로토타이핑이 필요해요

Native는 시간이 오래 걸립니다. Electron은 빠릅니다.

1. Electron이란?

핵심 특징

Electron은 웹 기술로 데스크톱 앱을 만드는 프레임워크입니다. 주요 장점:

  • 크로스플랫폼: Windows, macOS, Linux
  • 웹 기술: HTML, CSS, JavaScript
  • Node.js: 파일 시스템 접근
  • 자동 업데이트: 쉬운 배포
  • 대규모 생태계: VS Code, Slack, Discord

2. 설치 및 프로젝트 구조

설치

npm install -D electron

기본 구조

my-app/
├── main.js          # Main Process
├── preload.js       # Preload Script
├── renderer.html    # Renderer Process
└── package.json

package.json

{
  "name": "my-app",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^28.0.0"
  }
}

3. Main Process

// main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
    },
  });
  win.loadFile('renderer.html');
  // DevTools 열기
  win.webContents.openDevTools();
}
app.whenReady().then(() => {
  createWindow();
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

4. IPC (Inter-Process Communication)

Main → Renderer

// main.js
const { ipcMain } = require('electron');
ipcMain.handle('get-app-version', () => {
  return app.getVersion();
});
ipcMain.handle('read-file', async (event, filePath) => {
  const fs = require('fs').promises;
  return await fs.readFile(filePath, 'utf-8');
});

Preload Script

// preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
  getAppVersion: () => ipcRenderer.invoke('get-app-version'),
  readFile: (filePath) => ipcRenderer.invoke('read-file', filePath),
});

Renderer

<!-- renderer.html -->
<!DOCTYPE html>
<html>
  <body>
    <button id="btn">Get Version</button>
    <p id="version"></p>
    <script>
      document.getElementById('btn').addEventListener('click', async () => {
        const version = await window.electronAPI.getAppVersion();
        document.getElementById('version').textContent = version;
      });
    </script>
  </body>
</html>

5. React 통합

설치

npm install react react-dom
npm install -D @vitejs/plugin-react vite electron-builder

vite.config.ts

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
  plugins: [react()],
  base: './',
  build: {
    outDir: 'dist-react',
  },
});

main.js

const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  if (process.env.NODE_ENV === 'development') {
    win.loadURL('http://localhost:5173');
  } else {
    win.loadFile(path.join(__dirname, 'dist-react/index.html'));
  }
}
app.whenReady().then(createWindow);

React Component

import { useState, useEffect } from 'react';
export default function App() {
  const [version, setVersion] = useState('');
  useEffect(() => {
    window.electronAPI.getAppVersion().then(setVersion);
  }, []);
  return (
    <div>
      <h1>My Electron App</h1>
      <p>Version: {version}</p>
    </div>
  );
}

6. 파일 시스템

// main.js
const { ipcMain, dialog } = require('electron');
const fs = require('fs').promises;
ipcMain.handle('open-file', async () => {
  const { canceled, filePaths } = await dialog.showOpenDialog({
    properties: ['openFile'],
    filters: [{ name: 'Text Files', extensions: ['txt', 'md'] }],
  });
  if (canceled) return null;
  const content = await fs.readFile(filePaths[0], 'utf-8');
  return { path: filePaths[0], content };
});
ipcMain.handle('save-file', async (event, { path, content }) => {
  await fs.writeFile(path, content, 'utf-8');
  return true;
});

7. Auto Update

npm install electron-updater
// main.js
const { autoUpdater } = require('electron-updater');
app.whenReady().then(() => {
  createWindow();
  autoUpdater.checkForUpdatesAndNotify();
});
autoUpdater.on('update-available', () => {
  console.log('Update available');
});
autoUpdater.on('update-downloaded', () => {
  autoUpdater.quitAndInstall();
});

8. 빌드 및 배포

electron-builder

npm install -D electron-builder

package.json

{
  "scripts": {
    "build": "vite build",
    "dist": "electron-builder"
  },
  "build": {
    "appId": "com.example.myapp",
    "productName": "My App",
    "directories": {
      "output": "release"
    },
    "files": [
      "dist-react/**/*",
      "main.js",
      "preload.js"
    ],
    "win": {
      "target": "nsis"
    },
    "mac": {
      "target": "dmg"
    },
    "linux": {
      "target": "AppImage"
    }
  }
}

빌드

npm run build
npm run dist

9. Chromium과 Node.js 통합(아키텍처 심화)

Electron 앱은 하나의 제품처럼 보이지만, 런타임 관점에서는 Chromium 기반 UI 스택Node.js 런타임이 결합된 구조입니다. 이 결합이 Main/Renderer 분리·IPC·보안 모델의 전제가 됩니다.

프로세스 모델과 역할

  • Main 프로세스(browser): 앱의 “백엔드”에 가깝습니다. app, BrowserWindow, Menu, Tray, dialog, autoUpdater 등 OS·창·수명 주기를 다루는 API는 대부분 Main에서만 안전하게 사용할 수 있습니다. 여기서 Node.js가 기본 활성화되어 있으며, 파일 시스템·자식 프로세스·네이티브 모듈 로딩의 1차 진입점이 됩니다.
  • Renderer 프로세스: 사용자에게 보이는 웹 페이지(Chromium) 가 실행되는 공간입니다. 기본 설정에서는 웹과 유사한 샌드박스를 전제로 하며, nodeIntegration: false일 때는 require('fs') 같은 직접 접근이 차단됩니다. 필요한 OS 기능은 IPC로 Main에 위임하는 것이 정석입니다.

메시지 루프와 “한 앱처럼” 동작하기

Node.js는 libuv 기반 이벤트 루프를, Chromium은 자체 UI/네트워크/렌더링 루프를 가집니다. Electron은 이 둘을 같은 프로세스(Main) 안에서 통합해 타이머·I/O·윈도우 이벤트가 서로 배선되도록 합니다. 덕분에 “웹 UI + Node 백그라운드 작업”을 단일 데스크톱 앱으로 묶을 수 있지만, 반대로 무거운 동기 작업이 Main 스레드를 오래 점유하면 창이 멈추는 현상이 생깁니다. CPU·디스크 집약 작업은 Worker Thread, 별도 자식 프로세스, 또는 작업 큐 + 청크 처리로 Main의 반응성을 지키는 것이 운영 관점에서 중요합니다.

V8·버전 정합성

Renderer의 JavaScript는 Chromium에 포함된 V8 컨텍스트에서, Main의 Node 코드는 Electron이 번들한 Node ABI와 맞춰집니다. Electron 버전을 올리면 Node ABI와 네이티브 모듈 호환성이 함께 바뀌므로, 네이티브 의존성이 있는 앱은 업그레이드마다 재빌드·회귀 테스트가 필요합니다.


10. IPC 심화: Main ↔ Renderer

기본 예제의 invoke/handle요청–응답형 RPC에 가깝습니다. 프로덕션에서는 통신 패턴을 명확히 나누는 것이 유지보수와 보안 감사에 유리합니다.

패턴 비교

패턴API특징
비동기 요청–응답ipcRenderer.invoke / ipcMain.handlePromise 기반, 반환값 전달에 적합. 권장 기본값
이벤트 스트림ipcRenderer.send / ipcMain.on단방향 알림·진행률·푸시에 적합. 응답이 필요하면 별도 채널 또는 invoke 병행
메인→렌더러 푸시webContents.sendRenderer의 ipcRenderer.on으로 수신. 상태 브로드캐스트에 사용

직렬화와 비용

IPC 페이로드는 구조화 복제(Structured Clone) 가능한 데이터 위주로 전달됩니다. 대용량 버퍼·깊은 객체 트리를 매 틱마다 보내면 직렬화 비용이 커집니다. 대용량 파일은 Renderer에 “내용 전체”를 넘기기보다 Main에서 경로·스트림·청크 단위로 처리하거나, 꼭 필요하면 SharedArrayBuffer 같은 접근은 보안·격리 정책과 팀 가이드에 맞춰 신중히 선택합니다.

채널 명명·검증

채널 문자열은 스펙처럼 관리하는 편이 좋습니다. ipcMain.handle('read-file', …)에 임의 경로를 그대로 넘기면 경로 조작 위험이 있습니다. Main 측에서는 허용 디렉터리 화이트리스트, 정규화된 절대 경로 검증, 심볼릭 링크 주의 같은 서버 코드와 동일한 방어를 적용합니다.

// main.js — 경로 검증 예시(개념)
const path = require('path');
const ALLOWED_ROOT = path.resolve(app.getPath('userData'), 'safe-root');

ipcMain.handle('read-sandboxed-file', async (event, relPath) => {
  const target = path.resolve(ALLOWED_ROOT, relPath);
  if (!target.startsWith(ALLOWED_ROOT + path.sep)) {
    throw new Error('path outside sandbox');
  }
  return await fs.readFile(target, 'utf-8');
});

event 객체와 보안 힌트

ipcMain 핸들러의 event어느 프레임에서 왔는지 등 메타데이터를 담습니다. 다중 윈도우·webview를 쓰는 앱에서는 발신 webContents.id 검증이나 특정 창만 허용 같은 정책을 추가할 수 있습니다. “렌더러가 곧 신뢰할 수 없는 클라이언트”라는 전제를 유지하는 것이 안전합니다.


11. 컨텍스트 격리(Context Isolation)와 보안

contextIsolation: true가 의미하는 것

true이면 Preload 스크립트의 JavaScript 컨텍스트웹 페이지(앱 UI)의 컨텍스트가 분리됩니다. 페이지 스크립트는 window에 직접 붙은 Node 기능을 볼 수 없고, Preload가 contextBridge로 노출한 API만 호출할 수 있습니다. 이는 임의 사이트 XSS가 곧 파일 시스템 접근으로 이어지는 것을 끊는 핵심 방어선입니다.

nodeIntegration: false와의 조합

Renderer에서 Node를 끄는 설정은 기본적으로 공격 표면을 줄입니다. UI는 DOM·Fetch 중심으로 두고, 권한이 필요한 작업은 IPC + Main으로 모읍니다. 예외적으로 nodeIntegration: true가 필요한 레거시가 있다면, 가능한 한 별도 창·별도 출처로 격리하고 팀 리스크를 문서화하는 것이 좋습니다.

sandbox 옵션

sandbox: true(지원·호환성 확인 필요)는 Renderer를 Chromium 샌드박스에 더 가깝게 묶는 방향입니다. Electron 버전에 따라 동작·제약이 다르므로, 도입 시 공식 문서의 해당 버전 섹션회귀 테스트가 필요합니다.

웹 보안 기본기

  • webSecurity: 프로덕션에서는 일반적으로 true를 유지하고, 로컬 파일·CORS 이슈는 프로토콜 등록(protocol.registerFileProtocol 등) 으로 정식 해결하는 편이 낫습니다.
  • CSP(Content-Security-Policy): HTML을 조립할 때 인라인 스크립트·원격 스크립트 허용 범위를 최소화합니다. 인라인 onclick, 문자열로 조립한 eval 은 피합니다.
  • remote 모듈: 과거 편의 API였으나 보안·유지보수 문제로 제거/비권장 계열에 속합니다. 신규 코드는 IPC로 대체합니다.

창·탐색 하드닝

window.open, 새로운 BrowserWindow, 외부 URL 로드사용자 의도와 정책에 맞게 제한합니다. will-navigate / setWindowOpenHandler허용 도메인만 열기, 나머지는 기본 브라우저로 위임하는 패턴이 흔합니다.


12. 네이티브 모듈 로딩

Node 네이티브 애드온(.node)은 바이너리 ABI에 맞춰 컴파일됩니다. Electron은 자체 Node 버전을 포함하므로, 시스템에 설치된 Node용으로 빌드된 모듈을 그대로 가져오면 로드 실패·런타임 크래시가 날 수 있습니다.

@electron/rebuild와 빌드 파이프라인

의존성 설치 후 Electron ABI에 맞게 재컴파일하는 도구로 @electron/rebuild 가 널리 쓰입니다. CI에서는 OS별 빌드 에이전트에서 각 타깃용 아티팩트를 만들고, electron-builder 등으로 묶습니다.

npm install --save-dev @electron/rebuild
npx electron-rebuild

어디에 로드할 것인가

  • Main 프로세스: 파일 감시, 압축, OS API 래핑 등 서버형 네이티브 작업에 적합합니다.
  • Renderer: 가능하더라도 공격 표면·안정성 측면에서 권장되지 않는 경우가 많습니다. 꼭 필요하면 공식 가이드·보안 설정을 따르고, 대안으로 Main에서 처리 후 IPC를 우선 검토합니다.

순수 JS 대안

sqlite3 같은 네이티브 의존성은 배포·업데이트 비용이 큽니다. 요구 성능이 허용되면 better-sqlite3 vs sql.js 등 트레이드오프를 평가하고, 팀 표준으로 “네이티브 의존성 추가는 RFC” 규칙을 두는 경우도 많습니다.


13. 프로덕션 Electron 패턴

개발자 도구가 열린 채로 배포되거나, 로그에 시크릿이 남거나, 단일 인스턴스 없이 설정 파일이 깨지는 문제는 운영 품질을 떨어뜨립니다. 아래는 현장에서 자주 쓰는 패턴입니다.

단일 인스턴스·글로벌 단축키

const gotLock = app.requestSingleInstanceLock();
if (!gotLock) {
  app.quit();
} else {
  app.on('second-instance', () => {
    // 이미 떠 있는 창 포커스
  });
}

환경 분리와 시크릿

  • API 키·토큰·라이선스 키는 Renderer 번들에 박지 않습니다. 필요 시 Main에서 OS 보안 저장소런타임 구성을 사용합니다.
  • NODE_ENV 또는 앱 전용 플래그로 디버그 메뉴·실험 기능을 게이트합니다.

로깅·크래시

  • Main: 파일 로그, OS 로그 연동 등.
  • Renderer: 민감 정보 마스킹 후 Main으로 전달하거나, Sentry 등 Electron 지원 SDK 패턴을 따릅니다.

업데이트·서명

electron-updaterHTTPS 업데이트 서버, 서명된 빌드(특히 macOS/Windows)와 함께 쓸 때 신뢰 체인이 완성됩니다. 내부 배포 채널이라도 무결성 검증은 기본입니다.

ASAR·리소스

앱 리소스는 asar 아카이브로 묶이는 경우가 많습니다. 런타임에 쓰기 가능한 경로userData문서화된 API를 사용합니다.

DevTools·메뉴

프로덕션 빌드에서는 openDevTools() 호출을 제거하거나 플래그로만 허용합니다. 디버그 빌드와 릴리스 빌드를 스크립트/환경변수로 분리합니다.


정리 및 체크리스트

핵심 요약

  • Electron: 웹 기술로 데스크톱 앱
  • 크로스플랫폼: Windows, macOS, Linux
  • Chromium + Node: Main은 Node 중심, Renderer는 Chromium·웹 모델(기본은 직접 fs 비권장)
  • IPC: invoke/handle 중심의 RPC, 필요 시 send/이벤트 스트림·Main→Renderer 푸시
  • 보안: contextIsolation: true, nodeIntegration: false, CSP·탐색 제한·채널 입력 검증
  • 네이티브 모듈: Electron ABI에 맞춘 재빌드(@electron/rebuild), 가능하면 Main에 집중
  • 프로덕션: 단일 인스턴스, 시크릿 분리, 로그·업데이트·서명·asar·DevTools 게이트
  • Node.js: 파일 시스템 접근(주로 Main)
  • Auto Update: 자동 업데이트
  • React/Vue: 프레임워크 통합

구현 체크리스트

  • Electron 설치
  • Main Process 구현
  • Renderer 구현
  • IPC 통신 구현
  • React/Vue 통합
  • 파일 시스템 접근
  • Auto Update 설정
  • 빌드 및 배포
  • (심화) IPC 채널 명세·Main 입력 검증·CSP·프로덕션 하드닝

같이 보면 좋은 글


이 글에서 다루는 키워드

Electron, Desktop, Cross-platform, IPC, Node.js, Chromium, 보안, TypeScript, React

내부 동작과 핵심 메커니즘

이 글의 주제는 「Electron 완벽 가이드 | 크로스플랫폼 데스크톱 앱·IPC·Auto Update·실전 활용」입니다. 앞선 튜토리얼을 구현·런타임 관점에서 다시 압축합니다. 요청 경로와 상태 전이를 기준으로 “입력이 어디서 검증되고, 핵심 연산이 어디서 일어나며, 부작용(I/O·네트워크·디스크)·동시성이 어디서 터지는가”를 한 장면으로 그리면 장애 분석이 빨라집니다.

처리 파이프라인(개념도)

flowchart TD
  A[입력·요청·이벤트] --> B[파싱·검증·디코딩]
  B --> C[핵심 연산·상태 전이]
  C --> D[부작용: I/O·네트워크·동시성]
  D --> E[결과·관측·저장]

경계에서의 지연·실패(시퀀스 관점)

sequenceDiagram
  participant C as 클라이언트/호출자
  participant B as 경계(프로세스·런타임·게이트웨이)
  participant D as 의존성(외부 API·DB·큐)
  C->>B: 요청/이벤트
  B->>D: 조회·쓰기·RPC
  D-->>B: 지연·부분 실패·재시도 가능
  B-->>C: 응답 또는 오류(코드·상관 ID)

알고리즘·프로토콜·리소스 관점 체크포인트

  • 불변 조건(Invariant): 각 단계가 만족해야 하는 조건(버퍼 경계, 프로토콜 상태, 트랜잭션 격리, 파일 디스크립터 상한)을 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
  • 결정성: 동일 입력에 동일 출력이 보장되는 순수 층과, 시간·네트워크·스레드 스케줄에 의해 달라질 수 있는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
  • 경계 비용: 직렬화/역직렬화, 문자 인코딩, syscall 횟수, 락 경합, GC·할당, 캐시 미스처럼 누적 비용을 의심 목록에 넣습니다.
  • 백프레셔: 생산자가 소비자보다 빠를 때(소켓 버퍼, 큐 깊이, 스트림) 어디서 어떤 신호로 속도를 줄일지 정의합니다.

프로덕션 운영 패턴

실서비스에서는 기능과 함께 관측·배포·보안·비용·규제가 동시에 요구됩니다.

영역운영 관점 질문
관측성요청 단위 상관 ID, 에러율/지연 분위수(p95/p99), 의존성 타임아웃·재시도가 대시보드에 보이는가
안전성입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가
신뢰성재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가
성능캐시 계층·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가
배포롤백 룬북, 카나리/블루그린, 마이그레이션 호환성·플래그가 문서화되어 있는가
용량피크 트래픽·디스크·파일 디스크립터·스레드 풀 상한을 주기적으로 검증하는가

스테이징은 데이터 양·네트워크 RTT·동시성을 가능한 한 프로덕션에 가깝게 맞추는 것이 재현율을 높입니다.


확장 예시: 엔드투엔드 미니 시나리오

「Electron 완벽 가이드 | 크로스플랫폼 데스크톱 앱·IPC·Auto Update·실전 활용」을 실제 배포·운영 흐름으로 옮긴 체크리스트형 시나리오입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.

  1. 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드 표를 API 또는 이벤트 경계에 둔다.
  2. 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 한 화면(로그+메트릭+트레이스)에서 추적한다.
  3. 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
  4. 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지(또는 피처 플래그) 확인한다.
  5. 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값이 기대 범위인지 본다.

의사코드 스케치(프레임워크 무관)

handle(request):
  ctx = newCorrelationId()
  validated = validateSchema(request)        // 경계에서 거절
  authorize(validated, ctx)                  // 권한·테넌트
  result = domainCore(validated)             // 순수에 가까운 규칙
  persistOrEmit(result, idempotentKey)       // I/O: 멱등·재시도 정책
  recordMetrics(ctx, latency, outcome)
  return result

문제 해결(Troubleshooting)

증상가능 원인조치
간헐적 실패레이스, 타임아웃, 외부 의존성 불안정, DNS최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검
성능 저하N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거
메모리 증가캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납상한·TTL·힙/FD 스냅샷 비교
빌드·배포만 실패환경 변수, 권한, 플랫폼 차이, lockfileCI 로그와 로컬 diff, 런타임·이미지 버전 핀
설정이 로컬과 다름프로필·시크릿·기본값, 지역 리전단일 소스(예: 스키마 검증된 설정)와 배포 매트릭스 표준화
데이터 불일치비멱등 재시도, 부분 쓰기, 캐시 무효화 누락멱등 키·아웃박스·트랜잭션 경계 재검토

권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.

자주 묻는 질문 (FAQ)

Q. Tauri와 비교하면 어떤가요?

A. Electron이 더 성숙하고 생태계가 큽니다. Tauri는 더 가볍고 빠릅니다.

Q. 번들 크기는 어떤가요?

A. 기본적으로 100MB+ 입니다. Chromium과 Node.js가 포함되기 때문입니다.

Q. 보안은 어떤가요?

A. contextIsolation: truenodeIntegration: false를 기본으로 두고, 권한은 IPC로 Main에 위임하며, CSP·탐색·외부 링크 정책으로 공격 표면을 줄이는 것이 핵심입니다. Renderer는 신뢰할 수 없는 클라이언트로 가정하고, IPC 인자는 서버 입력처럼 검증합니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, VS Code, Slack, Discord 등이 Electron으로 만들어졌습니다.

Q. 네이티브 모듈이 Electron에서만 로드 오류가 납니다.

A. 시스템 Node용으로 빌드된 .node 바이너리는 Electron의 Node ABI와 다를 수 있습니다. @electron/rebuild로 Electron 버전에 맞게 다시 빌드하고, CI에서 OS별 아티팩트를 검증합니다.