일렉트론 12 렌더링 프로세스에서 node 사용하는 방법

 

Main 과 Renderer 프로세스

일렉트론에는 크게 두개의 프로세스 종류가 있다. 메인프로세스와 렌더러 프로세스 두 종류의 프로세스를 사용한다. 메인프로세스는 머플리케이션의 윈도우 창을 생성하고 관리하는 역활을 하며, 렌더러 프로세스는 윈도우 창 내에서 웹페이지를 렌더링하는 역활을 한다. 렌더링 프로세스와 메인프로세스간에는, IPC를 통해 통신 할 수 있다.

메인 프로세스는 윈도우 창을 관리하는 역활을 하기때문에, 가능한 작업(i/o 등)들은 메인프로세스에서 하면 안된다. 혹시 메인프로세스에서 이러한 작업이 발생하게 되면, 프로그램은 해당 작업이 끝날때까지 응답없음 상태가 되어버린다. 하지만 렌더링 프로세스는, 웹페이지를 렌더링할뿐인 프로세스기 때문에, 이러한 작업을 해도, 전체 어플리케이션에는 아무런 지장이없다. 따라서 대부분의 작업은 렌더러 프로세서에서 수행하는것이 권장된다.

렌더링 프로세스 에서 node.js를 사용하기

일렉트론은, node.js를 사용하여 만들어져 있고, 어플리케이션을 만들때도 자유롭게 사용할 수 있다. 다만, 최근버전에서는 보안을 이유로 렌더러 프로세스에서 node를 바로 사용할 수 없다.

오래된 일렉트론 버전을 이용한 블로그 포스팅 들에는 렌더러 프로세스에서 그냥 node.js를 사용한다. 하지만 최근버전에서 node.js의 기능들을 사용하려고 하면 에러를 만나게 된다.

const Jimp = require("jimp");
Uncaught ReferenceError: require is not defined
    at image_view.js:1

예를들어 npm 을 이용해 jimp를 깔았다면 위와같이 렌더러 프로세스에서 jimp패키지를 로드하려고 할 것이다. 최신버전의 일렉트론에서는 ReferenceError를 만나게 된다. https://www.electronjs.org/docs/tutorial/security#isolation-for-untrusted-content 이유는, 일렉트론 최신버전에서 nodeIntegration이 비활성화 되고, contextIsolation을 기본적으로 활성화 하기 때문이다. 렌더러 프로세스에서는 이제 렌더링시점에 node를 돌릴수 없기에 이전처럼 node를 사용하려고 하면 에러가 나게된다.

contextIsolation

따라서, 이제는 그냥 node.js를 사용할 수 없고 contextBridge를 사용하는 방법을 이용해야 한다. 해당기능은, api를 preload 스크립트에 짜고, 해당 api를 렌더링 프로세스에서 이용하는 방식이다. 렌더링 프로세스에는 preload 스크립트를 지정할 수 있다. 렌더링 프로세스를 실행하기전에, node.js 관련 패키지들을 먼저 로드하거나, 렌더러 프로세스의 dom element에 영향을 주게끔 할수도 있다.

preload.js

const Jimp = require("jimp");

async function loadImage(img_src) {
    console.log(img_src);
    var jimpSrc = await Jimp.read(img_src);
    return jimpSrc.bitmap;
}

contextBridge.exposeInMainWorld('imageApi', {
    loadImage: (imgSrc) => loadImage(imgSrc),
});

renderer.js

window.imageApi.loadImage('./manga.png')
});

위 코드는, jimp를 이용해 이미지를 로드하는 api를 생성한 코드이다. 콘텍스트 브릿지를 생성 하기위해서는 preload에 api를 생성해준다. contextBridge.exposeInMainWorld 함수를 사용하면 되며, 첫번째 파라메터로는 api 이름을 정해주고, 두번째 파라메터에 상세한 api를 작성해 주면 된다. 나는 jimp를 이용해 이미지를 로드하여 bitmap 데이터를 리턴하는 loadImage라는 api를 만들고, preload.js 내의 ~loadImage 함수를 이용하도록 api를 생성하였다. 실제 renderer에서 사용하기 위해서는, window.api_name.api() 식으로 사용하면 된다.