회사에서 윈도우프로그램과 웹 소켓으로 통신하는 데스크탑 프로그램을 만드는 프로젝트를 맡게 되었다.
(필자는 이 프로젝트를 시작함과 동시에 '오예 벨로그에 쓸거 생겼다' 라는 생각에 들떴다는건 비밀)
이에 본인의 기록용 포스팅이라는 베이스를 두고 누군가 필요한 사람을 위해 강좌 형식으로 적도록 하겠다.
본디 기록용 포스팅 일 뿐이어서, 불친절한 시리즈인건 안비밀
필자는 yarn이 아닌 npm을 주로 사용한다.
사용된 버전
node: v12.20.0
npm, npx: v6.14.8
react : 17.0.1
electron-is-dev: 1.2.0
electron: 11.2.0
electron-builder: 22.9.1
typescript: 4.1.3
wait-on: 5.2.1
cross-env: 7.0.3
concurrently: 5.3.0
npx create-react-app 앱이름 --template typescript
npm이 아닌 npx로 앱을 생성한다. npx를 사용하면 최신버전의 CRA로 React가 실행되는 환경을 만들 수 있다.
우리는 타입스크립트를 사용할 것이기 때문에 뒤에 뒤에 --template typescript
는 필수.
react 프로젝트가 성공적으로 생성 되었다면,
해당 앱 폴더로 이동하여 Electron과 각종 개발에 편의성을 주는 도구들을 설치한다.
npm i electron-is-dev
npm i electron electron-builder concurrently cross-env wait-on typescript --save-dev
해당 모듈들은 (electron-is-dev 제외) 런타임에서 사용되지 않을 개발용 모듈이므로 --save-dev
인수를 추가해준다.
Electron-is-dev
: 개발환경인지 빌드한 프로덕션환경인지 확인을 위하여 사용됨.Electron
: 일렉트론을 실행하기 위해서 사용됨.Electron-builder
: 일렉트론을 실제 프로덕션 버전으로 빌드하기 위해 사용됨.concurrently
: 동시에 여러 명령어를 사용(병렬적으로)하기 위해 사용됨.cross-env
: 프로그램을 CLI환경에서 실행 시킬 때에, OS에 관계 없이 환경변수를 설정할 수 있도록 하기 위해 사용됨.wait-on
: HTTP 자원, port, file등이 활성화 될 때 까지 기다려주는 cross platformtypescript
: typescripttsconfig는 각자 알아서 작성하시길....
위에서 모든것이 완료되었다면, public 폴더 안에 Electron을 실행하는 ts파일을 하나 작성해준다.
import { app, BrowserWindow } from 'electron';
import * as isDev from 'electron-is-dev';
import * as path from 'path';
let mainWindow: BrowserWindow;
const createWindow = () => {
mainWindow = new BrowserWindow({
width: 900,
height: 680,
center: true,
kiosk: !isDev,
resizable: true,
fullscreen: false,
fullscreenable: true,
webPreferences: {
// node환경처럼 사용하기
nodeIntegration: true,
enableRemoteModule: true,
// 개발자도구
devTools: isDev,
},
});
// production에서는 패키지 내부 리소스에 접근.
// 개발 중에는 개발 도구에서 호스팅하는 주소에서 로드.
mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`);
if (isDev) {
mainWindow.webContents.openDevTools({ mode: 'detach' });
}
mainWindow.setResizable(true);
// Emitted when the window is closed.
mainWindow.on('closed', () => (mainWindow = undefined!));
mainWindow.focus();
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
프로젝트 파일 내의 package.json
파일을 다음과 같이 수정해준다.
{
...
"main": "public/electron.js",
"homepage": "./",
"scripts": {
"react-start": "react-scripts start",
"react-build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"start": "tsc ./public/electron.ts && concurrently \"cross-env BROWSER=none npm run react-start\" \"wait-on http://localhost:3000 && electron .\"",
"build": "npm run react-build && electron-builder",
"release": "npm run react-build && electron-builder --publish=always",
"lint": "eslint './src**/*.{ts,tsx}'"
},
...
}
main : 프로그램의 진입점이므로 꼭 설정해주어야함. 일렉트론을 실행하는 코드이다.
scripts :
dist
폴더에 production 실행파일을 생성해준다.npm run start
를 터미널에 입력해주면 다음과 같이 앱이 뜨고, 가운데 리액트 마크가 삥글삥글 돈다면 성공적으로 완료되었다.