개발 이야기/frontend

Electron에서 React의 특정 페이지를 로드하는 방법

thisisamrd 2024. 8. 6.

오늘은 제가 electron.js와 react를 연동하는 어플리케이션을 만들면서 여러번 삽질했던 내용 중 하나인, react의 특정 페이지를 electron.js내에서 불러온 뒤 팝업시키는 방법에 대해 포스팅 해보겠습니다.

아래서도 언급하겠지만 hash router를 사용하는 것이 핵심입니다. 

 

 

 

electron.js와 react를 연동하는 초기 세팅 방법에 대해서는 아래 링크를 참조하세요.

 

 

 

이후 나올 내용은 리액트와 Electron.js를 사용하여 특정 페이지를 팝업으로 띄우는 방법입니다.

 

 

 

 

1. React Router 설정

우선 저희는 리액트에서 HashRouter를 사용해야 합니다.

리액트에서 라우트를 설정할 때 HashRouter를 사용하여 다음과 같이 페이지를 정의할 수 있습니다.

import React from "react";
import { HashRouter as Router, Routes, Route } from "react-router-dom";
import Login from "./components/Login/Login";
import ConsultationCall from "./components/ConsultationCall/ConsultationCall";
import CallList from "./components/CallList/CallList";

// App 함수 컴포넌트 정의
function App() {
	return (
		<Router>
			<div className='App'>
				<Routes>
					<Route path='/login' element={<Login />} />
					<Route path='/calllist-popup' element={<CallList />} />
					<Route path='/consultation-call-popup' element={<ConsultationCall />} />
				</Routes>
			</div>
		</Router>
	);
}

export default App;

 

 

Hash Router를 사용해야 하는 이유

 

Electron은 기본적으로 파일 프로토콜을 사용하여 애플리케이션을 로드합니다. BrowserRouter를 사용할 경우, 경로가 서버로 직접 요청되어야 하는데, 파일 프로토콜에서는 이 방식이 작동하지 않습니다. 서버로의 요청이 없기 때문에, URL에 대한 직접적인 리소스 접근이 이루어지지 않습니다.

 

HashRouter는 클라이언트 측 라우팅을 통해 이러한 문제를 해결합니다. 해시 부분은 서버로 요청되지 않으며, 브라우저에서만 해석되기 때문에 Electron 환경에서도 문제없이 작동할 수 있습니다. 이 해시 라우터를 electron의 main.js에서 어떻게 불러와야 하는지에 대해서는 아래서 마저 기술하겠습니다.

 

 

 

2. Electron의 load URL 설정

const { app, BrowserWindow } = require('electron');
const path = require('path');
const isDev = require('electron-is-dev');

function createMainWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    },
  });

  mainWindow.loadURL(
    isDev
      ? "http://localhost:3000#/"
      : `file://${path.join(__dirname, "my-react-app/build/index.html")}#/`
  );
}

function createLoginWindow() {
  const loginWindow = new BrowserWindow({
    width: 400,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
    },
  });

  loginWindow.loadURL(
    isDev
      ? "http://localhost:3000#/login"
      : `file://${path.join(__dirname, "my-react-app/build/index.html")}#/login`
  );
}

app.on('ready', () => {
  createMainWindow();
  // 원하는 위치에서 createLoginWindow를 호출하여 팝업창을 열 수 있습니다.
  createLoginWindow();
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createMainWindow();
  }
});

 

 

여기서 주목해야 할 부분은 이것입니다.

  loginWindow.loadURL(
    isDev
      ? "http://localhost:3000#/login"
      : `file://${path.join(__dirname, "my-react-app/build/index.html")}#/login`
  );

 

 

isDev 구분

우선 isDev가 무엇인지 설명드릴게요. isDev 변수를 사용하여 애플리케이션이 개발 환경인지 프로덕션 환경인지를 구분합니다. 개발 환경(isDev가 true인 경우)에서는 create-react-app의 기본 개발 서버를 사용하고, 프로덕션 환경(isDev가 false인 경우)에서는 빌드된 정적 파일을 사용합니다.

저는 각 환경에 따라 로딩 방식을 다르게 하기 위해 위와 같이 코드를 적었습니다.

 

HashRouter 사용

 

이제 앞서 리액트에서 설정한 해시라우터를 위의 코드와 같이 설정합니다.

 

  • 개발 환경에서는 http://localhost:3000#/login을 사용합니다.
  • 프로덕션 환경에서는 로컬 파일 시스템에서 애플리케이션을 로드하기 위해 file:// URL을 사용합니다.

URL의 해시(#/login) 부분을 사용하여 리액트 라우터에서 특정 페이지를 직접 지정합니다. 해시를 사용하여 클라이언트 측에서만 라우팅을 처리하므로, Electron이 파일 시스템에서 리소스를 불러올 때 경로 문제를 피할 수 있습니다.

 

 

 

이제 개발서버를 실행하거나 프로덕션 모드에서 실행할 경우, Electron 애플리케이션이 시작될 때 app.on('ready', createLoginWindow)를 통해 위에서 맵핑한 로그인 페이지가 잘 열리는 것을 확인할 수 있을 것입니다.

 

댓글