---
id: "imported/blog/study/til/electron"
title: "Electron 강좌"
description: "Electron 강좌 관련 기록."
kind: "record"
published: "2021-01-27T00:00:00.000Z"
tags: ["electron"]
url: "https://www.readiz.com/blog/study/til/electron/"
markdownUrl: "https://www.readiz.com/blog/study/til/electron/index.md"
---

# Electron 강좌

## Basic of Electron (Udemy 강의)

- <https://samsungu.udemy.com/> 으로 드가면 들을 수 있음.
- <https://samsungu.udemy.com/course/electron-react-tutorial/learn/lecture/6986540?start=0#content>

## Basic of Electron

- 플랫폼. 데스크톱 앱을 만들기 위함.
- 웹 앱은 최근들어 굉장하게 복잡해졌다. Electron은 이러한 특성을 데스크톱 앱에서 사용하기 위해 등장한 플랫폼이라고 보면 됨.
- 기본적으로 생각해야할 부분은 웹 브라우저는 유저의 하드디스크에 접근이 불가능하다는 것. 이러한 제약을 풀어주는 것이 Electron 이라는 플랫폼이라고 생각하면 된다.
  - 사용자의 컴퓨터 리소스에 접근 가능하게 된다는 점이 핵심!!
- Electron === Google Chrome (Mostly..)
  - Task Manager를 보면 Google Chrome Helper라는 놈이 여러개가 같이 존재함. 이것을 이해하면 Electron을 이해하는 데에 도움이 된다.
  - 왜 다른 프로세스가 같이 도는가?
    - 같이 죽지 않게 하기 위해. 랜더링 이슈를 막기 위해. Isolate 시키기 위해.
    - RendererProcess가 핵심임. 이 프로세스가 웹페이지를 그린다.
    - IPC(Inter Process Communication)을 통해 MainWindow, RendererProcess들이 통신한다.
    - 웹브라우저와 다른 점은, 웹브라우저의 주소표시줄과 같은 완전 브라우저 자체의 내용까지도 접근이 가능하다는 점.
- Electron의 역사(?)
  - GitHub -> Electron -> Atom (지금은 VS Code가 먹었지만..)
  - GitHub는 처음에 Atom을 위해 Electron을 만들었고(Atom은 JS 유저가 많아 JS로 만들었다 함), 이것이 쓸만하다고 판단해서 Open Source로 만들었음
  - 이것을 Slack, Discord, VS Code 등에서 사용하기 시작했다.

## Handling Electron Project

- Electron (Run at terminal, Overall Chrome Process로 생각) -> Create MainWindow(BrowserWindow) -> index.html을 로딩.
  - BrowserWindow를 생성하는 로직 또한 js로 작성한다는 점! (타 언어 사용 0%)
- nodemon을 사용하면 지속적인 F5 키를 눌러야 하는 것을 방지할 수 있음.  -> 자동 시작을 해주는 서버 side에서는 이미 자주 쓰이고 있는 녀석임
- 아래 명령어는, src/js/index.js 디렉토리에서 코드변화가 감지하면 재시작을 하도록 설정.

```js
  "start": "npm-run-all --parallel watch:webpack watch:nodemon",
  "watch:webpack": "webpack --config=webpack.config.js --mode=development --watch",
  "watch:nodemon": "nodemon --exec \"electron .\" --watch \"./src/js/setup.js\""
```

- Step by Step Guide
  - npm init
  - package.json 생성
  - npm install --save electron
  - 2 파일 생성 필요. init을 위한 js 과 보여줄 index.html
  - init을 위한 js는 터미널에서 실행된다. node를 통해.. 여기서는 require만 사용 가능
    - const electron = require('electron');
    - import는 node에서 기본적으로 지원되진 않음.
  - `app` 은 overall process 를 의미함.
  ```js
  const { app } = require('electron');
  ```
  - app은 `event`를 방출하며, 이것은 app.on 으로 청취 가능함
    - Event Driven Programming
  - `app` 만 실행해서는 사실 아무것도 진행되지 않음!
    - 이후 BrowserWindow를 만들어야 함, 그래야 사용자에게 브라우저가 보이게 된다.
    - `app` 은 처음 로딩이 끝나면 `ready` 이벤트를 가져온다. 그 후 mainWindow를 생성하는 것이 일반적인 Electron App의 패턴.
    - `app` 에 전체 Main Process의 Life Cycle이 엮여 있다고 보면 됨.
  - BrowserWindow
    - `new BrowserWindow()` 만 해도 바로 뭔가 나온다.
    - 개발자 도구도 바로 튀어나오게 됨 원한다면.
    - 그러나 주소 표시줄 같은 것은 기본적으로 없다.
    - 위에서 본 app과는 다른 녀석임. 완전히 다른 Process 라고 생각하면 됨
    - 처음 만들기만 하면 html document가 load되지 않았으므로 빈 화면만 나오게 된다.
      - 불러오기 위해서는 `new BrowserWindow().loadURL('https://google.com')` 와 같이 하면 됨
      - 물론 local file도 불러오기 가능하며 대부분의 ELectron App은 로컬 앱을 만드는 것이기 때문에 로컬 파일을 불러올 것임.
    - 특수한 Node.js 함수를 실행하기 전에는 일반 웹 개발 하는 것과 동일하게 개발이 진행되게 된다. HTML / JS / CSS를 얼마나 잘 다루느냐에 따라 앱 개발 속도가 달라지게 된다.
      - 차이점은 Local HDD를 접근가능하느냐 마느냐 정도로 생각해도 됨
      - ffmpeg 같이 node.js를 통해 interact 하기 쉬운 cli process와 소통하기도 좋다.
    - BrowserWindow 부분을 Web App Side라고 할 수 있는데, 이 부분은 `Keep as generic as posslbie` 한게 좋다. 그래야 나중에 재사용성에 유리함.
  - App <-> BrowserWindow 소통 방법?
    - IPC 시스템을 사용함
      - IPC: Inter Process Communication
    - `const { ipcMain } = require('electron')`
      - Main 에서 쓰이는 IPC object.
    - `const { ipcRenderer } = require('electron')`
      - 랜더러 프로세스에서 사용하는 IPC
    - `ipcRenderer.send('eventName', 'Data')`
      - 형태만 딱 봐도 사용하기 쉽지\~
      - 이건 랜더러 프로세스에서 메인으로 메시지 보내기 위해서 쓰는 것
      - 메인에서 받기 위해서는 `ipcMain.on` 을 사용
    - `mainWindow.webContents.send`
      - 랜더러 프로세스로 보낼 때 쓰는 것. BrowserWindow 객체를 참조하여 보내게 됨
      - 받을 때는 `ipcRenderer.on` 을 사용
  - 예제에서는 ffmpeg 관련된 동작은 BrowserWindow Process 에서 처리하지 않고, App Process에서 처리하는 식으로 구현했음. 이게 좀 더 바람직해 보이기도 함.

## Status Tray Application

- `Tray` 와 `BrowserWindow` 는 당연하게도 다르다.
- `Tray Icon`을 만드는 방법?
  - `new Tray(iconPath)`
  - `tray.on('click', () => { mainWindow.show(); });` 자주 쓰이는 패턴
- `Tray` 근처에 창을 생성하는 방법? (특히 OS, 사용자마다 위치가 다를 것..)
  - `click` 이벤트가 올 때, `bounds` 객체가 전달된다. 이 객체에 x, y 좌표가 제공됨. 이것을 참고하여 window 의 위치를 조절하면 된다.
  - `mainWindow`에 `setBounds`를 설정하면 지정한 영역에 윈도우를 잘 생성할 수 있다.

## ETC (다른 강의 내용 포함)

- app 의 webContent에 `new-window` 이벤트에 `preventDefault`를 걸어두면 링크에서 새 창이 뜨는 것을 막을 수 있음.
- session은 모든 browserWindow와 공유 됨. `mainWindow.webContents.session`
  - `const {session} = require('electron')` 도 같은 값 참조.
    - `session.defaultSession`
  - custom session도 만들 수 있긴 하다.
  - `cookie` 도 `session`의 하위 object 임.
  - download 도 control 가능하다. (창 안뜨고 자동 다운 가능)
  - `globalShortcut` : 화면이 떠 있지 않더라도 전체적으로 등록되는 Shortcut
    - 심지어 앱이 켜져있지 않더라도 실행됨! 그러나 충돌나는 것은 알아서 회피해야 할 것..
- `const {screen} = require('electron')`을 통해서 스크린에 관련된 모든 데이터를 가져올 수 있음
  - getAllDisplay(): 전체 연결된 display에 대한 정보들을 가져올 수 있다.
    - touchSupport 등등 포함..
- Main Process가 BrowserWindow를 소유하며, Browser Window는 Renderer Process 그 자체다.
  - Main Process는 여러개의 BrowserWindow를 소유한다.
- BrowserWindow는 webFrame > webContents 를 소유한다.
  - ex) Zoom Factor
- `electron.desktopCapturer`: 데스크탑의 화면을 저장 가능함
- `process.version`: 각 버전을 가지고 있음..
  - ex) chrome, napi, electron, v8, opensssl 등등..
- `process.hang()`: Renderer를 Hang을 걸 수 있음.
- `process.crash()`: crash 될 때를 시뮬레이팅 할 수 있음.
  - 이 때 reload 걸면 복구될 수 있음. 복구 되는게 낫나?..
- 몇몇 electron API들은 Shared API로, renderer와 main 모두에게서 쓰일 수 있음. (ex: `shell` 등..)
  - electron.remote 안써도 된다는 뜻

## Distribution

- Electron-Builder 가 진리.
  - cli 옵션도 지원한다. 어떤 platform으로 distribute 할지는 이걸로 결정
  - 결과물은 dist 디렉토리에 제공됨.
- 제대로 하려면 code-signing도 해야 함. (아마 mac은 더 강제되는듯?)
- Electron-Builder에 이미 AutoUpdater가 있다.
  - GitHub 를 통해 배포하려면, Personal access token을 발급받아야 한다.
  - 이를 등록하면, 빌드 후 자동으로 GitHub release에 올려버릴 수 있음. (이미 만들어진 tag를 참조해서 올리는 듯?)
- (참고) setx 커맨드를 윈도우에서 사용하면 환경변수를 잠시 설정할 수 있다.
- 자동 업데이트는 electron-updater와 함께\~
