์ด๋ฒ ํฌ์คํธ์์๋ ์ค์ ๋ก ์ผ๋ ํธ๋ก ์คํ ํ๊ฒฝ์ ๊ตฌ์ถํด๋ณผ ๊ฒ์ ๋๋ค. ์ด์ ํฌ์คํธ๋ฅผ ๋ณด๊ณ ์ค๋ฉด, ๋ ์ดํด๊ฐ ์ฌ์ธ ๊ฒ์ ๋๋ค.๐
โญ react ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค
npx create-react-app react-electron-project
โญ ํ๋ก์ ํธ์ ์ผ๋ ํธ๋ก ํจํค์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค.
npm install --dev electron
โญ package.json์์ electron ๊ด๋ จ ์ค์ ์ ์ถ๊ฐํฉ๋๋ค.
{
...
"main" : "src/main.js"
"scripts" : {
...
"electron" : "electron ."
}
}
-> ์ผ๋ ํธ๋ก ์ entry point๋ฅผ main.js๋ก ์ค์ ํฉ๋๋ค.
-> electron : electron ์ ์ผ๋ ํธ๋ก ์คํ ์คํฌ๋ฆฝํธ๋ฅผ ๋ํ๋
๋๋ค.
โญ src/main.js๋ฅผ ๋ง๋ญ๋๋ค.
const { app, BrowserWindow } = require('electron');
const path = require('path')
function createWindow() {
const win = new BrowserWindow({
width : 800,
height : 600,
webPreferences : {
nodeIntergration : true,
contextIsolation : true,
preload : path.join(__dirname, 'preload.js'),
},
})
win.loadURL('http://localhost:3000')
}
app.whenReady().then(() => {
createWindow()
})
app.on('window-all-closed', function() {
if (process.platfrom !=='darwin') app.quit()
})
-> ๋ฆฌ์กํธ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ ์ํด, win.loadFile์ win.loadURL('http://loacalhost:3000')๋ก ๋ณ๊ฒฝํฉ๋๋ค.
โญ react์ electron์ ๊ฐ์ด ์คํํ๊ธฐ ์ํด ๋ค์ ์๋ ํจํค์ง๋ฅผ ์ถ๊ฐํฉ๋๋ค.
npm install --dev concurrently wait-on
-> concurrently : ์ผ๋ ํธ๋ก ๊ณผ ๋ฆฌ์กํธ ํ๋ก์ธ์ค๋ฅผ ๋์์ ์คํํ ์ ์๋ ํจํค์ง ์
๋๋ค.
-> wait-on : ํ๋ก์ธ์ค ๋์ ์ํ์ ํ๊ฐ์ ํ๋ก์ธ์ค๊ฐ ์๋ฃ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ค ์๋ฃ๋ ํ ๋ค์ ํ๋ก์ธ์ค๋ฅผ ์ํํ๊ฒ ๋ง๋ค์ด ์ค๋๋ค.
โญ package.json์ ์คํฌ๋ฆฝํธ๋ฅผ ๋ณ๊ฒฝํฉ๋๋ค.
"scripts": {
"start": "concurrently \"npm:react-start\" \"npm:electron-start\"",
"react-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron": "electron .",
"electron-start": "wait-on http://localhost:3000 && electron ."
},
โญ ๋ธ๋ผ์ฐ์ ์ฐฝ์ ๋ถํ์ํ๋ฏ๋ก, .env ํ์ผ ์์ฑ ํ BROWSER=none์ด๋ผ๋ ๋ด์ฉ์ ์ถ๊ฐํด ์ค๋๋ค
์ด์ , ํ๋ก์ ํธ๋ฅผ ์คํํ๋ฉด ์ผ๋ ํธ๋ก ์์ ๋ฆฌ์กํธ๋ฅผ ์คํํ ํ๋ฉด์ด ๋์ฌ ๊ฒ์
๋๋ค.
๋ฆฌ์กํธ ์ฝ๋๋ฅผ ๋ณ๊ฒฝ์ ๋ฐ๋ก ๋ฐ์์ด ๋๊ณ , ๋ธ๋ผ์ฐ์ ์ฐฝ๊ณผ ํจ๊ป ๋์ค๊ธฐ ๋๋ฌธ์ electron์ ์ถ๊ฐ๋ก ์คํํด์ฃผ์ง ์์๋ ๋๋ค๋ ํธ๋ฆฌํจ์ ์ป๊ฒ ๋์์ต๋๋ค. โบ
์ด์ ํฌ์คํธ์์ ์ ๋ฆฌํ๋ preload.js๋ฅผ ์ค์ ๋ก ํ์ฉํด ๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค ๊ฐ api ํต์ ์ฝ๋๋ฅผ ์์ฑํด๋ณด๊ฒ ์ต๋๋ค.
์ฌ์ค, react์ electron์ ํจ๊ป ์ฌ์ฉํ ๋ ๊ธฐ์กด์ react์ ๋ฌ๋ผ์ง๋ ์ ์ด ํฌ๊ฒ๋ ์์ ๊ฒ์ ๋๋ค.
๋ง์ฝ ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ nodejs์ ๋ชจ๋์ ๊ฐ์ ธ์์ผ ํ ํ์๊ฐ ์๋ค๋ฉด preload ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๊ฒ ์ง๋ง ๊ทธ ์ด์ธ์๋ api ํต์ ์ ํ๋ ๊ฒ ์๋๊ณ ์ ๊ธฐ์กด์ react์๋ ํฌ๊ฒ ๋ค๋ฅธ ์ ์ด ์๊ธฐ ๋๋ฌธ์ ์ฝ๊ฒ ์ ์ํด ์ฑ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ๐
// ipcHandlers.js
const axios = require('axios');
async function handleSignIn(event, {userId, password}) {
try {
const res = await axiosInstance.post('/user/login', {userId, password});
return res.data;
} catch (error) {
console.error(error)
}
}
module.exports = {
handleSignIn
}
// main.js
const ipcHandlers = require('./ipcHandlers');
function createWindow() {
...
app.whenReady().then(() => {
createWindow();
ipcMain.handle('signIn', ipcHandlers.handleSignIn); โญ
});
...
}
-> 'signIn'์ด๋ผ๋ ์ฑ๋์ handleSignIn listner๋ฑ๋ก
// preload.js
const { contextBride, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
signIn : ({ userId, password}) => ipcRenderer.invoke('signIn', {userId, password}),
})
-> 'signIn' ์ฑ๋ ํธ์ถ
// App.tsx
function App() {
// ์ ์ญ์ ์ผ๋ก ์ ์ธ๋ electronAPI ๊ฐ์ ธ์ค๊ธฐ
const signIn = (window as any).electronAPI.signIn;
const [accessToken, setAccessToken] = useState();
useEffect(() => {
signIn({userId : '1', password : '1'})
.then((res) => {
setState(res.accessToken);
})
.catch((err) => {
console.error(err);
})
}, []);
retrn (
<>
<div>{accessToken}</div>
</>
-> ์ด๋ ๊ฒ ๋ ๋๋ฌํ๋ก์ธ์ค์์ preload์์ ํธ์ถํ signIn ์ฑ๋์ ํจ์๋ฅผ ๊ฐ์ ธ์ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
+++ ์ฐธ๊ณ ๋ก electron์์๋ BrowserRouter๊ฐ ์๋, HashRouter๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.