[Electron] Electron의 main과 renderer 프로세스

minidoo·2020년 8월 23일
8

Electron

목록 보기
2/4

이전 게시글에서 Electron과 Nextron에 대해 간단히 알아봤습니다!
Electron은 JavaScript, html, css를 사용하여 데스크탑 앱을 만드는 프레임워크입니다. 웹에서도 앱을 만들 수 있는 좋은 플랫폼이죠 :-)

main 프로세스

Electron에서 메인 프로세스는 main 스크립트를 실행하는 프로세스를 말합니다. Electron 앱은 항상 하나의 메인 프로세스를 가집니다.

import { BrowserWindow } from 'electron';

...

win = new BrowserWindow({
  ...options,
  ...state,
  webPreferences: {
    width: 1000,
    height: 600,
    nodeIntegration: true,
    ...options.webPreferences,
  },
});

메인 프로세스는 BrowserWindow 인스턴스를 생성하여 웹페이지를 만듭니다. width와 height 값을 입력하여 페이지 크기를 조절할 수 있습니다.

만약, 화면 가득 채우고 싶다면 width와 height 값 대신 fullscreen: true를 사용하면 됩니다 :)


환경변수 (Path)

본격적으로 background.js를 살펴보기 전에 알아두면 좋은 환경변수 몇 가지를 알아보겠습니다.

  • process.env.NODE_ENV : 저장된 환경설정 값 (개발 or 운영 모드)
  • process.env.HOME : Local Home 디렉토리 경로
  • process.execPath : node의 실행파일의 절대 경로
  • process.browser : browser 상태일 때 true
  • __dirname : 현재 실행 중인 폴더 경로

프로젝트를 진행하면서 가장 헤맸던 부분이 바로 환경변수입니다 :-(
개발과 운영 환경을 구분하지 않아서 개발 모드일 때 잘 돌아가던 프로그램이 운영 모드에서는 에러가 발생하더라구요.

또 Electron에서 사용할 수 있는 경로가 따로 있기 때문에 더 어려웠던 것 같아요. 이 부분은 이후 게시물에서 더 자세히 다뤄볼께요!


background.js

import { app } from 'electron';
import serve from 'electron-serve';
import { createWindow } from './helpers';

const isProd = process.env.NODE_ENV === 'production';

if (isProd) {
  serve({ directory: 'app' });
} else {
  app.setPath('userData', `${app.getPath('userData')} (development)`);
}

...

우선 process.env.NODE_ENV 환경변수를 사용해 개발과 운영 모드를 구분할 필요가 있습니다. 위 코드는 프로젝트가 저장되는 경로를 설정하는 부분입니다.

개발 모드의 경우에 (development)로 구분한 것을 볼 수 있는데요, 운영과 개발 프로젝트를 함께 저장하면 캐시가 겹쳐 향후 문제가 발생할 수 있기 때문입니다.

getPath('userData')는 Electron에서 사용되는 함수 중 하나입니다. /userData 폴더를 만들어서 해당 폴더에 프로젝트를 저장합니다.

...

(async () => {
  await app.whenReady();

...

  if (isProd) {
    await mainWindow.loadURL('app://./home.html');
  } else {
    const port = process.argv[2];
    await mainWindow.loadURL(`http://localhost:${port}/home`);
    mainWindow.webContents.openDevTools();
  }
})();

...

본격적으로 프로그램이 실행됐을 때의 코드입니다.

개발 모드에서 실행 명령어를 통해 프로그램을 작동시키면 보통 http://localhost:3000 에 접속해 볼 수 있습니다.

운영 모드의 경우 loadURL이라는 명령어를 통해 app 폴더에 있는 /home.html가, 개발 모드의 경우에는 http://localhost:${port}/home 페이지가 실행됩니다.

여기서 중요한 것은 운영 모드는 html 파일 자체가, 개발 모드는 home page가 실행된다는 점입니다. 쉽게 말해 운영 모드는 파일이, 개발 모드는 서버가 돌아간다는 것인데요! 실행할 때마다 서버가 돌아간다면 메모리도 많이 차지하고 비용도 올라가겠죠? 때문에 운영 모드는 서버로 구동하지 않는 것이 효율적이라고 합니다 :-)

...

app.on('window-all-closed', () => {
  app.quit();
});

마지막으로 window-all-closed 이벤트를 통해 윈도우를 닫으면 앱이 종료되는 코드입니다. Electron에서 사용되는 app으로 생명주기를 조절할 수 있습니다. 지원되는 다양한 함수와 이벤트를 통해 Electron 생명주기를 조절하는 연습을 해봐야 할 것 같아요!

Electron에서의 app : https://www.electronjs.org/docs/api/app


renderer 프로세스

제가 사용한 Nextron은 Next.js를 사용합니다.
Next.js는 React를 기반으로 SSR(Server Side Rendering)을 제공하는 편리한 프레임워크입니다.

Server Side Rendering (SSR)

서버 사이드 랜더링은 서버 랜더링을 통해 미리 View를 만들어 JavaScript가 로드되기 전에 Page를 보여줍니다. 따라서 초기 로딩 속도를 줄여준다는 장점이 있죠!

저는 SSR의 특징 때문에 페이지 로드 구현 시 어려움을 있었습니다 : (

프로그램을 최초로 실행했을 때 / home.jsx 페이지가 실행된다고 가정해보겠습니다. 앞서 말했듯이 SSR 방식을 통해 페이지가 로드됩니다.

Next.js는 Link 컴포넌트를 사용해 <Link href="/"><a>Home</a></Link> 페이지를 이동할 수도 있지만 js에서 코드를 입력하여 이동시킬 수도 있습니다.

바로 Router.Push()location.href 입니다. 둘은 아주 큰 차이가 있는데, SSRCSR을 결정짓는 부분이라고 할 수 있습니다! Router.push()는 이동될 페이지를 CSR로 불러오는 반면, location.hrefSSR로 불러오게 됩니다. 즉, SSR은 이동될 페이지에서 다시 한번 새로고침이 이루어 진다는 것을 의미합니다.

만약 기억해야 할 의미있는 정보가 있다면 location.href는 조금 위험한 방법일 수 있겠죠?


Next.js

renderer는 실제 페이지를 보여주는 프로세스이기 때문에 Next.js의 문법 그대로 사용하면 됩니다!

import React, { useState, useEffect } from 'react';
import 'antd/dist/antd.css';

function Home() {

  const [label, setlabel] = useState('');
  
  useEffect(() => {
  	console.log('Change label');
  }, [label]);

  const inputContent = e => {
    setlabel(e.target.value);
  }
  
  const btnClick = () => {
    if(!label) {
      return alert('input your information')
    }
  }
  
return (
    <div className="home-wrap">
      <Input size="large" value={label} onChange={inputContent}/>
      <Button type="primary" onClick={btnClick}>Save</Button>   
    </div>
  );
};

export default Home;

React의 useState를 사용하여 값을 저장하고 변경하며 useEffect를 통해 생명주기를 조절할 수 있습니다.

화면을 그리고 이벤트를 적용하는 코드 자체는 기존 JavaScript를 사용하여 큰 어려움이 없었지만 Next.js의 생명주기SSR과 같은 특성 때문에 헤맸던 부분도 있었습니다 :)


마무리하며

오늘은 main 프로세스와 renderer 프로세스에서 조심해야 할 부분들에 대해 알아봤습니다. main 프로세스에서는 개발과 운영 모드에 따라 코드를 분리해야 한다는 점, renderer 프로세스는 사용하는 프레임워크의 특성을 적용해야 한다는 점이 중요합니다!

다음 게시글에서는 main 프로세스와 renderer 프로세스의 통신인 IPC에 대해 알아보겠습니다. 오늘도 들려주셔서 감사합니다 :0

0개의 댓글