← 기록 / TIL

Electron 강좌

Electron 강좌 관련 기록.

이 글의 목차
  1. Basic of Electron (Udemy 강의)
  2. Basic of Electron
  3. Handling Electron Project
  4. Status Tray Application
  5. ETC (다른 강의 내용 포함)
  6. Distribution

Basic of Electron (Udemy 강의)

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 디렉토리에서 코드변화가 감지하면 재시작을 하도록 설정.
  "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 를 의미함.
    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와 함께~