본문 바로가기
개발/Electron

일렉트론 - 리액트 프로젝트 빌드하기 (Build Electron App with React)

by 피로물든딸기 2024. 1. 2.
반응형

Electron 전체 링크

 

참고

- Hash Router로 gh-pages 배포하기

 

리액트 프로젝트를 먼저 생성하자.

yarn create react-app react-with-electron

 

설치가 완료되었다면, 생성한 프로젝트로 이동하자.

cd react-with-electron

 

이제 electron을 설치한다.

npm install electron

 

앱 개발 환경을 구분하기 위한 패키지 electron-is-dev를 설치한다.

npm install electron-is-dev

 

여러 명령어를 병렬 실행하기 위해 concurrently를 설치한다. (리액트 + 일렉트론 실행)

npm install concurrently

 

특정 조건을 만족할 때까지 기다리기 위해 wait-on을 설치한다. (리액트 실행 후 일렉트론 실행)

npm install wait-on

 

package.json을 다음과 같이 수정한다. (entry point = public/elecron.js)

  "main": "public/electron.js",
  "homepage": "./",
  "scripts": {
    "start": "concurrently \"react-scripts start\" \"npm run electron\" ",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "electron": "wait-on http://localhost:3000 && electron ."
  },

 

public 폴더 아래에 electron.js를 생성한다.

electron-is-dev로 loadURL이 상황에 따라 달라지게 하였다.

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

let win;

function createWindow() {
    win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
    },
  });

  win.loadURL(
    isDev
      ? "http://localhost:3000"
      : `file://${path.join(__dirname, "../build/index.html")}`
  );

  win.on("closed", function () {
    win = null;
  });
}

app.whenReady().then(createWindow);

app.on("window-all-closed", function () { // 모든 창이 닫혔을 때 발생하는 이벤트
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", function () { // app이 활성화될 때 발생하는 이벤트
  if (win === null) {
    createWindow();
  }
});

 

이제 npm run start를 실행해보자.

 

웹 브라우저 일렉트론 App이 실행된다.

웹 브라우저는 필요가 없기 때문에 root 폴더에 .env를 생성하여 환경 변수를 설정한다.

BROWSER=none


빌드하기

 

이제 electron-builder를 설치하자.

npm install electron-builder

 

scripts에 pack 변수를 아래와 같이 추가한다.

  "scripts": {
    ...
    "electron": "wait-on http://localhost:3000 && electron .",
    "pack": "npm run build && electron-builder build -c.extraMetadata.main=build/electron.js"
  },

 

그리고 electronelectron-builderdevDependencies로 이동한다.

  "dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "concurrently": "^8.2.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "wait-on": "^7.2.0",
    "web-vitals": "^2.1.0"
  },

  "devDependencies": {
    "electron": "^28.1.0",
    "electron-builder": "^24.9.1"
  },

 

그리고 build를 아래와 같이 추가한다.

  "build": {
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },

 

이제 npm run pack을 실행하자.

npm run pack

 

dist 폴더에 win-unpacked 폴더 아래에 exe 파일이 생성된 것을 알 수 있다.

 

파일을 실행하면 정상적으로 리액트-일렉트론 앱이 동작하는 것을 알 수 있다.

 

package.json은 다음과 같다.

{
  "name": "react-with-electron",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "concurrently": "^8.2.2",
    "electron-is-dev": "^2.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.21.1",
    "react-scripts": "5.0.1",
    "wait-on": "^7.2.0",
    "web-vitals": "^2.1.0"
  },
  "devDependencies": {
    "electron": "^28.1.0",
    "electron-builder": "^24.9.1"
  },
  "build": {
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "directories": {
      "buildResources": "assets"
    }
  },
  "main": "public/electron.js",
  "homepage": "./",
  "scripts": {
    "start": "concurrently \"react-scripts start\" \"npm run electron\" ",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "electron": "wait-on http://localhost:3000 && electron .",
    "pack": "npm run build && electron-builder build -c.extraMetadata.main=build/electron.js"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

라우터 설정하기

 

마지막으로 리액트 라우터 코드를 추가하여 라우팅이 제대로 설정되는지도 확인해 보자.

npm install react-router-dom

 

데스크탑에서는 BrowserRouter가 동작하지 않기 때문에 Hash Router를 사용한다.

index.js에 HashRouter를 추가한다.

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { HashRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <HashRouter>
    <App />
  </HashRouter>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

page 폴더에 Home.js, Router1.js, Router2.js를 추가한다. (아래는 Home.js 예시)

import React from "react";

const Home = () => {
  return <div>Home</div>;
};

export default Home;

 

App.js를 아래와 같이 수정한다.

import { Route, Link, Routes } from "react-router-dom";

//routing components
import Home from "./page/Home";
import Router1 from "./page/Router1";
import Router2 from "./page/Router2";

function App() {
  return (
    <div className="App">
      <div>
        <p>
          <Link to="/">홈</Link>
        </p>
        <p>
          <Link to="/r1">Router1</Link>
        </p>
        <p>
          <Link to="/r2">Router2</Link>
        </p>
      </div>
      <div>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/r1" element={<Router1 />} />
          <Route path="/r2" element={<Router2 />} />
        </Routes>
      </div>
    </div>
  );
}

export default App;

 

npm run start로 라우터 동작을 확인해 보자.

그리고 npm run pack으로 빌드된 일렉트론도 정상 동작이 되는지 확인해 보자.

반응형

댓글