본문 바로가기
공부/etc

[Electron] Electron에서 코드 변경사항 빠르게 적용하기 (feat. electron-reload)

by Piva 2024. 6. 30.
  • Electron을 사용하며 불편했던 것 중 하나는, 웹 개발을 하던 때와 달리 자동으로 변경사항이 적용되지 않는다는 것이었다. 때문에 코드를 고치고, 이미 열려있는 Electron 창을 닫고, 커맨드 창에서 다시 Electron을 실행하는 불편함이 있었다.
  • 이를 개선하기 위한 방법을 알아보고, 실제 적용해본 내용을 공유한다.

electron-reload 적용하기

  Electron에 자동 리로드를 추가할 때 자주 거론되는 방법. 공식 문서에서 설명하는 사용방법도 비교적 간단하다. 간단하다면 간단한데, 나는 프로젝트에서 타입스크립트를 사용하고 있어서 이런 저런 추가 설정을 더했고, 만족스럽지 못한 부분이 있다.

 

// 설치
npm install electron-reload

 

  npm 등으로 라이브러리를 설치하면 electron_reload 함수를 임포트하여 사용할 수 있다. electron_reload 함수는 아래와 같은 인자를 받는다.

 

  • paths: 변화를 감지할 파일이나 디렉터리를 받는다.
  • options: 기타 리로드 관련 설정을 받는다.
    • electron: Electron 실행파일의 위치.
    • electronArgv: Electron 실행파일에 넘길 매개변수 배열.
    • forceHardReset: main 파일 뿐 아니라 모든 파일에 대한 변경에 hard reset을 적용한다.
      ※ Hard reset: 새로운 Electron 프로세스를 시작하는 방식으로 리로드를 진행한다.

  위에서 언급한 Hard reset 방식을 사용하지 않는다면 Electron browser(WebContents)만 리로드되며, 적용 방법 또한 매우 간단하다. 그냥 변경을 감지할 파일이나 디렉터리의 paths를 전달하기만 하면 된다.

 

import { app, BrowserWindow, dialog } from "electron";
import * as path from "path";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const electronReload = require('electron-reload');

let mainWindow: BrowserWindow | null = null;

function createWindow() {
  mainWindow = new BrowserWindow({
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
    width: 800,
  });

  if (!app.isPackaged) {
  	// 변경을 감지할 파일 혹은 디렉터리를 설정한다
    electronReload(__dirname);
  }
  
  /* 후략 */
}
  • app.isPackaged 를 사용한 이유는, 패키징했을 때 electron-reload로 인해 발생하는 에러를 사전에 방지하기 위해서다. app.isPackaged는 패키징하지 않은 상태에선 false를 반환하기 때문에 개발환경에서만 reload를 활성화시키는 것이 가능하다.

 

  다만 Electron 자체를 리로드 하는 Hard reset 방식을 위해선 Electron 실행파일의 경로를 넣어주어야 한다. 이는 공식 문서에 설명되어 있듯 node_modules 내부의 electron 폴더로 설정해주면 된다.

 

import { app, BrowserWindow, dialog } from "electron";
import * as path from "path";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const electronReload = require('electron-reload');

let mainWindow: BrowserWindow | null = null;

function createWindow() {
  /* 생략 */

  if (!app.isPackaged) {
    electronReload(__dirname, {
      electron: path.join(__dirname, 'node_modules', '.bin', 'electron'),
    });
  }
}

 

 

타입스크립트 프로젝트에서 사용하기

  내가 해당했던 경우. 타입스크립트로 작성된 스크립트를 JS로 컴파일 한 결과물을 Electron으로 실행하고 있기 때문에 그냥 위와 같은 설정만 해선 제대로 변경사항이 반영되지 않는다. 변경사항이 제대로 반영되도록 tsc 명령어로 일단 컴파일을 한 번 진행한 후, 그 다음에 electron을 실행해야 한다. 이를 위해 concurrently 라이브러리를 사용한다.

 

  concurrently를 사용하면 여러 개의 명령어를 동시에 실행할 수 있다. 그러므로 tsc -w 명령어로 파일의 변화를 타입스크립트가 자동으로 감지하고 컴파일하도록 한 후, 그 결과물의 변화를 감지한 electron-reload가 Electron을 자동적으로 리로드시킬 수 있게 한다.

 

// package.json
{
    "scripts": {
        "hot-start": "concurrently \"tsc -w\" \"electron ./dist/main.js\""
    },
}

 

리로드가 실행되는 모습

 

윈도우 환경에서의 설정

  여기에서 언급되는 이슈. 레포지터리나 위 예시에서 설정한 것처럼 Electron 실행파일의 경로를 설정하면 윈도우에선 잘 동작하지 않는다. 따라서 실행환경에 따라 Electron 실행파일의 경로를 다르게 설정해주어야 한다.

 

import { app, BrowserWindow, dialog } from "electron";
import * as path from "path";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const electronReload = require('electron-reload');

let mainWindow: BrowserWindow | null = null;

function createWindow() {
  /* 생략 */

  if (!app.isPackaged) {
    electronReload(__dirname, {
      electron: path.join(
        __dirname,
        'node_modules',
        '.bin',
        process.platform === 'win32' ? 'electron.cmd' : 'electron'),
    });
  }
}
  • process.platform을 사용해 현재 실행환경을 확인하고, 윈도우 환경일 경우 electron.cmd 로 경로를 설정해준다.

 

+) nodemon 사용하기

  위의 방식을 사용하여 리로드를 사용할 수 있게 된 것까지는 좋았으나, 윈도우 환경에서는 다른 문제가 발생했다. 리로드가 발생할 때마다 새로운 cmd 창이 열리고, 전에 열린 cmd 창이 닫히지 않는 것이다. 심각한 문제는 아니지만 개발을 계속할 수록 cmd 창이 늘어나기 때문에 따로 닫는 것도 귀찮아진다.

 

  알아보니 다른 사람들도 이미 겪은 문제로, electron-reload 라이브러리를 사용하는 대신 nodemon을 사용해 리로드를 구현한 예가 있었다. electron-reload 라이브러리보다는 느리지만, 상기 언급한 문제가 해결된다고. 

 

  다른 대안이 있나 찾아봤는데, nodemon 을 사용하는 것과 비슷하게 기동한다는 electronmon 라이브러리를 발견했다. 이런저런 방법이 있으니 다양한 방법을 시도해보는 것도 좋을 것 같다.

 


 

Electron - チュートリアルその4 ホットリロードを実現する electron-reload の使い方 - pystyle

前回作成した Electron のサンプルコードでは、main.cjs や index.html を変更した場合、一度アプリを終了し、再度起動する必要がありました。これでは、開発中は不便です。 今回は、ファイルの

pystyle.info