์ด๋ฒ ํฌ์คํธ๋, ์ค์ ์คํํ๋ ๋ชจ์ต์ด ์๋ electron์ ์ฌ์ฉํ ๋ ์ดํดํ๊ณ ์์ด์ผ ํ๋ ๊ธฐ๋ณธ์ ์ธ ๊ฐ๋ ๋ค์ ๋ํด ์ ๋ฆฌํ์ต๋๋ค.
Electron์ HTML, CSS, Javascript๋ฅผ ์ฌ์ฉํด desktop application์ ๋ง๋ค๊ธฐ ์ํ ํ๋ ์์ํฌ ์ ๋๋ค. Chromium๊ณผ Node.js๋ฅผ single binary file์ ์ถ๊ฐํจ์ผ๋ก์จ, Electron์ Javascript ์ฝ๋ ๋ฒ ์ด์ค๋ก Windows, macOS, Linux์์ ๋์ํ๋ cross-platfrom-apps๋ฅผ ๋ง๋ค ์ ์๊ฒ ํด์ค๋๋ค.
์ด๋ฐ ์ ์๋ฅผ ๊ฐ์ง Electron์ Javascript ๋ฟ๋ง ์๋๋ผ React, Nextjs์๋ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ํ Next์ Electron์ ๋ ์ ์ฐํ๊ฒ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ ๋๊ตฌ๋ก Nextron์ด ์กด์ฌํ๋๋ฐ, ์ฐ๋ฆฌ์ ํ๋ก์ ํธ๋ React + Electron์ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
์ผ๋ ํธ๋ก ์ ๋ฉ์ธ(main)ํ๋ก์ธ์ค์ ๋ ๋๋ฌ(renderer)ํ๋ก์ธ์ค, ๋๊ฐ์ง ํ๋ก์ธ์ค๊ฐ ์กด์ฌํฉ๋๋ค.
์ผ๋ ํธ๋ก ์ฑ์ ๋จ ํ๋์ ๋ฉ์ธ ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ง๊ณ , ๋ฉ์ธ ํ๋ก์ธ์ค๋ Node.js ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๋ฉฐ ๋ฉ์ธ ํ๋ก์ธ์ค์์๋ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ค์ ๊ด๋ฆฌํ๊ณ ๊ฐ๊ฐ์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ์๋ก ๋
๋ฆฝ์ ์ผ๋ก ๋์ํฉ๋๋ค.
๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค ๊ฐ์ ํต์ ์ด ์ด๋ค์ ธ์ผ ํ๋๋ฐ, ์ผ๋ ํธ๋ก ์์๋ ์ด๋ฅผ ipcMain๊ณผ ipcRenderer์ ๊ฐ์ IPC ๋ชจ๋์ ํตํด ํ๋ก์ธ์ค ๊ฐ์ ํต์ ์ ์ด๋ฃจ๊ณ ์์ต๋๋ค.
์ฐ๋ฆฌ๋ ํ๋ก์ ํธ์ ๋ฃจํธ ํด๋์ main.js๋ผ๋ ํ์ผ์ ๋ง๋ค์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
electron์ ์ค์นํ ํ, package.json์์ "main":"main.js"๋ผ๋ ์ฝ๋๋ฅผ ๋ฃ์ด์ค ๊ฒ์
๋๋ค. ์ด๋ main.js๋ ๋ชจ๋ Electron ์ ํ๋ฆฌ์ผ์ด์
์ entry point๋ผ๋ ๊ฒ์ ๋ํ๋
๋๋ค.
์ด ์คํฌ๋ฆฝํธ๋ Node.js ํ๊ฒฝ์์ ์คํ๋๋ main process๋ฅผ ์ ์ดํ๋ฉฐ ์ฑ์ lifecycle ์ ์ด, ๊ธฐ๋ณธ ์ธํฐํ์ด์ค ํ์, ๊ถํ์ด ์๋ ์์ ์ํ ๋ฐ render processes ๊ด๋ฆฌ๋ฅผ ํฉ๋๋ค.
main.js์ ์ฝ๋๋ฅผ ์๋์ฒ๋ผ ์ ๋ ฅํ๋ค๊ณ ์๊ฐํด ๋ด ์๋ค.
// main.js
console.log(`Hello from Electron ๐`);
์ผ๋ ํธ๋ก ์ main process๋ Node.js runtime์ด๋ฏ๋ก electron ๋ช ๋ น์ผ๋ก ์์์ Node.js ์ฝ๋๋ฅผ ์คํํ ์ ์์ต๋๋ค. electron์ ์คํ์ํจ ํ, ํฐ๋ฏธ๋์ Hello from Electron ๐์ด ์ถ๋ ฅ๋๋ค๋ฉด, main process entry point๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋์๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
โญ electron์์ each window๋ local HTML ํ์ผ ๋๋ remote ์น ์ฃผ์์์ ๋ก๋ํ ์ ์๋ ์นํ์ด์ง๋ฅผ ํ์ํฉ๋๋ค.
ํ๋ก์ ํธ์ index.htmlํ์ผ์ด ์๋ค๋ ๊ฐ์ ํ์ main.js ํ์ผ์ ๋ด์ฉ์ ์๋์ฒ๋ผ ๋ฐ๊พผ๋ค๊ณ ์๊ฐํด ๋ด
์๋ค.
// main.js
const { app, BrowserWindow } = require('electron');
const createWindow = () => {
const win = new BrowserWindow({
width : 800,
height : 500,
})
win.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow()
})
์ฒซ๋ฒ์งธ ์ค์์๋ CommonJS ๋ชจ๋ ๊ตฌ๋ฌธ์ ์ฌ์ฉํด ๋ ๊ฐ์ Electron ๋ชจ๋์ ๊ฐ์ ธ์ต๋๋ค.
app : application์ lifecycle๋ฅผ ์ ์ดํฉ๋๋ค.
BrowserWindow : app windows๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํฉ๋๋ค.
๐ฉ ECMAScript ๋ชจ๋(import๊ตฌ๋ฌธ)์ ํ์ฌ Electron์์ ์ง์ ์ง์๋์ง ์์ต๋๋ค.
์ ์ฝ๋์์ ๋ง๋ createWindow() ํจ์๋ ์น ํ์ด์ง๋ฅผ ์ BrowserWindow ์ธ์คํด์ค๋ก ๋ก๋ํฉ๋๋ค. BrowserWindows๋ ์ฑ ๋ชจ๋์ ready ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ! ํ์๋ง ์์ฑํ ์ ์์ต๋๋ค.
์ด์ , electron์ ์คํํ๋ฉด ์น ํ์ด์ง๋ฅผ ํ์ํ๋ ์ฐฝ์ด ์ฑ๊ณต์ ์ผ๋ก ์ด๋ฆด ์ ์์ต๋๋ค.
์ฑ์ด ์ฐฝ์ ํ์ํ๋ ๊ฐ ์นํ์ด์ง๋ renderer process๋ผ๋ ๋ณ๋์ ํ๋ก์ธ์ค์์ ์คํ๋ฉ๋๋ค.
โ ์ด๋, renderer process๋ ์ผ๋ฐ์ ์ธ ํ๋ก ํธ์๋ ์น ๊ฐ๋ฐ์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋์ผํ JavaScript api ๋ฐ ๋๊ตฌ์ ์ก์ธ์ค ํ ์ ์์ต๋๋ค.
application windows๋ ์ด์์ฒด์ ๋ง๋ค ๋ค๋ฅด๊ฒ ์๋ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก ์ด๋ฌํ ๊ท์น์ ์ ์ฉํ๋ ๋์ ์ผ๋ ํธ๋ก ์ ์ฌ์ฉ์๊ฐ ์ด๋ฅผ ๋ฐ๋ฅด๊ณ ์ ํ ๊ฒฝ์ฐ ์ฑ ์ฝ๋์์ ์ด๋ฅผ ๊ตฌํํ ์ ์๋ ์ ํ๊ถ์ ์ ๊ณตํฉ๋๋ค.
์ฑ ๋ฐ, BrowserWindow ๋ชจ๋์์ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ์์ ํ์ฌ ๊ธฐ๋ณธ ์ฐฝ ๊ท์น์ ๊ตฌํํ ์ ์์ต๋๋ค.
electron์ ์คํํ ์ ์๋ ํ๋ซํผ ์ข ๋ฅ
- win32(Windows)
- linux(Linux)
- darwin(macOS)
window ๋ฐ linux์์ ๋ชจ๋ ์ฐฝ์ ๋ซ์ผ๋ฉด ์ผ๋ฐ์ ์ผ๋ก ์์ฉ ํ๋ก๊ทธ๋จ์ด ์์ ํ ์ข ๋ฃ๋ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ๋ง๋๋ ์ผ๋ ํธ๋ก ์ฑ์์ ์ด ํจํด์ ๊ตฌํํ๋ ค๋ฉด main.js์์ window-all-closed ์ด๋ฒคํธ๋ฅผ ์์ ํ๊ณ app.quit()๋ฅผ ํธ์ถํด ์ฌ์ฉ์๊ฐ ์ฑ์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ ์ข ๋ฃํฉ๋๋ค.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
์์ ์ฝ๋๋ฅผ main.js์ ์ ๋ ฅํ๋ฉด ์ฑ์ ๋ซ์์ ๋ ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
๐ฉ ๋ฐ๋๋ก macOS ์ฑ์ ์ผ๋ฐ์ ์ผ๋ก ์ฐฝ์ด ์ด๋ฆฌ์ง ์์๋ ๊ณ์ ์คํ๋ฉ๋๋ค. ์ฌ์ฉ ๊ฐ๋ฅํ ์ฐฝ์ด ์์ ๋ ์ฑ์ ํ์ฑํ ํ๋ฉด ์ ์ฐฝ์ด ์ด๋ฆฝ๋๋ค.
์ด ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ค๋ฉด ์ฑ ๋ชจ๋์ ํ์ฑํ ์ด๋ฒคํธ๋ฅผ ์์ ํ๊ณ ์ด๋ ค ์๋ BrowserWindows๊ฐ ์๋ ๊ฒฝ์ฐ ๊ธฐ์กด createWindow() ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWinodw.getAllWindows().length === 0) createWindow()
})
})
์ ์ฝ๋๋ฅผ main.js์ ์ถ๊ฐํ๋ฉด ์ด์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ฐฝ์ด ์์ ๋, ์ฑ์ ํ์ฑํ ํ๋ฉด ์ ์ฐฝ์ด ์ด๋ฆฌ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
โญ 2-1์ ๋ด์ฉ๋ค์ ๋ฐํ์ผ๋ก ๊ธฐ๋ณธ์ ์ธ main.js์ ๊ตฌ์ฑ์ ๋ณด์๋ฉด, ์๋์ ๊ฐ์ต๋๋ค.
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width : 800,
height : 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWinodw.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
๐บ preload script๋ ?
์ผ๋ ํธ๋ก ์ ๋ฉ์ธ ํ๋ก์ธ์ค๋ ์ ์ฒด ์ด์์ฒด์ ์ ๊ทผ ๊ถํ์ด ์๋ Node.js ํ๊ฒฝ์
๋๋ค. ์ผ๋ ํธ๋ก ๋ชจ๋ ์ธ์๋ Node.js ๋ด์ฅ ๋ฐ npm์ ํตํด ์ค์น๋ ๋ชจ๋ ํจํค์ง์ ์์ธ์ค ํ ์ ์์ต๋๋ค.
๋ฐ๋ฉด, ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ์น ํ์ด์ง๋ฅผ ์คํํ๊ณ ๋ณด์์์ ์ด์ ๋ก ๊ธฐ๋ณธ์ ์ผ๋ก Node.js๋ฅผ ์คํํ์ง ์์ต๋๋ค.
๊ทธ๋์ ์ผ๋ ํธ๋ก ์ ์๋ก ๋ค๋ฅธ ํ๋ก์ธ์ค(๋ฉ์ธ, ๋ ๋๋ฌ) ์ ํ์ ํจ๊ป ์ฐ๊ฒฐํ๋ ค๋ฉด preload๋ผ๋ ํน์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
-> ์ฆ, Node.js๋ฅผ ๋ ๋๋ฌ์์ ์ง์ ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ preload๋ฅผ ํตํด ๋ฐ์์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ผ ๋ณผ ์ ์์ต๋๋ค.
preload scripts๋ ์นํ์ด์ง๊ฐ renderer์ load ๋๊ธฐ ์ ์ ์ฃผ์
๋ฉ๋๋ค.
์ด ๋, ๋ ๋๋ฌ์ ํ์ํ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ค๋ฉด preload์์ contextBridge api๋ฅผ ํตํด global objects๋ฅผ ์ ์ํ ์ ์์ต๋๋ค.
๐ฉ preload experience
preload.js ํ์ผ์ ๋ฃจํธ ํด๋์ ์์ฑ ํ, ์๋์ฒ๋ผ Chrome, Node ๋ฐ Electron ๋ฒ์ ์ renderer์ ๋ ธ์ถํ๋ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
// preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node : () => process.versions.node,
chrome : () => process.versions.chrome,
electron : () => process.versions.electron,
})
preload ์คํฌ๋ฆฝํธ๋ฅผ renderer process์ ์ฐ๊ฒฐํ๊ธฐ ์ํด์ main.js์ BrowserWInodw ์์ฑ์์ webPreferences.preload ์ต์ ์ ์ ๋ฌํด์ผ ํฉ๋๋ค.
// main.js
const { app, BrowerWindow } = require('electron')
const path = require('path');
const createWindow = () => {
const win = new BrowserWindow({
width : 800,
height : 600,
webPreferences : {
preload : path.join(__dirname, 'preload.js'),
},
})
win.loadFie('index.html')
}
app.whenReady().then(() => {
createWinow()
})
- __dirname : ๋ฌธ์์ด์ ํ์ฌ ์คํ ์ค์ธ ์คํฌ๋ฆฝํธ์ ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
- path.join : ์ฌ๋ฌ ๊ฒฝ๋ก๋ฅผ ๊ฒฐํฉํด ๊ฒฐํฉ๋ ๊ฒฝ๋ก ๋ฌธ์์ด์ ์์ฑํฉ๋๋ค.
์ด์ renderer.js๋ผ๋ ํ์ผ์ด ์๋ค๋ ๊ฐ์ ํ์ ๋ฒ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค!
// renderer.js
const information = document.getElementById('info')
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
์ด์ , index.html์ renderer ์คํฌ๋ฆฝํธ๋ฅผ ๋ฃ์ผ๋ฉด ์ฑ ์คํ์ ๋ฒ์ ์ ๋ณด๊ฐ ๋์ค๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์์์ ๋งํ ๋ฐ์ ๊ฐ์ด, ์ผ๋ ํธ๋ก ์ ๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ์๋ก ๋ค๋ฅธ ์ญํ ์ ํ๋ฉฐ ์ํธ ๊ตํํ ์ ์์ต๋๋ค.
๋ค์ ํ ๋ฒ ์ ๋ฆฌํ์๋ฉด renderer process์์ ์ง์ node.js api์ ์ก์ธ์คํ๊ฑฐ๋ main process์์ HTML DOM์ ์ก์ธ์คํ ์ ์์ต๋๋ค.
๐ ์ด ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ์ฑ ์ ํ๋ก์ธ์ค ๊ฐ ํต์ (IPC)๋ฅผ ์ํด ์ผ๋ ํธ๋ก ์ ipcMin ๋ฐ ipcRenderer ๋ชจ๋์ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
์น ํ์ด์ง์์ main process๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ค๋ฉด ipcMain.handle์ ์ฌ์ฉํด main process handler๋ฅผ ์ค์ ํ ๋ค์ ipcRenderer.invoke๋ฅผ ํธ์ถํ๋ ํจ์๋ฅผ ์คํํ์ฌ preload script์์ handler๋ฅผ trigger ํ ์ ์์ต๋๋ค.
-> ์ ๊ฐ์ ๊ฒฝ์ฐ handler๋ก ํจ์๋ฅผ ๋ฑ๋กํ๊ณ ์ด๋ฅผ preload์์ ํธ์ถํ๋ค๊ณ ์ดํดํ์ต๋๋ค.
// renderer.js
const func = async () => {
const response = await window.versions.ping()
console.log(response) // prints out 'pong'
}
func()
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('versions', {
node : () => process.versions.node,
chrome : () => process.versions.chrome,
ping : () => ipcRenderer.invoke('์คํ'),
electron : () => process.versions.electron,
})
// main.js
const createWindow = () => {
const win = new BrowserWindow({
width : 800,
height : 600,
webPreferences : {
preload : path.join(__dirname, 'preload.js'),
},
})
ipcMain.handle('์คํ', () => '์คํ!')
win.loadFile('index.html')
}
์ฐ๋ฆฌ๋ main์์ '์คํ'์ด๋ผ๋ ์ฑ๋๋ก ํจ์๋ฅผ ๋ฑ๋กํ๊ณ , preload์์ '์คํ'์ด๋ผ๋ ์ฑ๋์ ํธ์ถํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ renderer ์คํฌ๋ฆฝํธ์์ ๋ถ๋ฌ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
-> ์ด๋ ๊ฒ ๋ ๋๋ฌ์์ node.js api๋ฅผ ์ง์ ๊ตฌํํ๋ ๊ฒ์ด ์๋, preload๋ฅผ ํตํด ๋ฉ์ธ๊ณผ ๋ ๋๋ฌ๊ฐ ํต์ ํ๋ ๋ฐฉ๋ฒ์ ์ ์ ์์ต๋๋ค.
์ฐ๋ฆฌ๊ฐ electron์ ์๋ก ๋ค๋ฅธ ํ๋ก์ธ์ค์ ํต์ ๋ฐฉ๋ฒ์ ์๋ฒฝํ ํ์ ํ๊ธฐ ์ํด์ , preload script๋ฅผ ์ฌ์ฉํด Node.js๋ฅผ import ํด์ค๋ ๊ฒ๊ณผ context-isolated renderer process์์ electron ๋ชจ๋์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ์ดํดํด์ผ ํฉ๋๋ค.
1) Renderer to main example
renderer process์์ main process๋ก ๋จ๋ฐฉํฅ IPC ๋ฉ์์ง๋ฅผ ์คํํ๋ ค๋ฉด ipcRenderer.send API๋ฅผ ์ฌ์ฉํด ๋ฉ์์ง๋ฅผ ๋ณด๋ธ ๋ค์ ipcMain.on api์์ ์์ ํ ์ ์์ต๋๋ค.
์๋ ์ฝ๋๋ ๋จ๋ฐฉํฅ ํต์ ์ ์์์ ๋๋ค.
// renderer.js
const seetButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
})
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle : title => ipcRenderer.send('set-title', title),
})
// main.js
const { app, BrowserWindow, ipcMain } = require("electron")
const path = require("path")
function createWindow() {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
})
ipcMain.on("set-title", (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
})
mainWindow.loadFile("index.html")
}
app.whenReady().then(() => {
createWindow()
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit()
})
2) Renderer to main example
์๋ฐฉํฅ IPC์ ์ผ๋ฐ์ ์ธ ์ ํ๋ฆฌ์ผ์ด์ ์ renderer process ์ฝ๋์์ main process ๋ชจ๋์ ํธ์ถํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ์ ๋๋ค.
์ด๋ ipcMain.handle๊ณผ ์์ ์ด๋ฃจ๋ ipcRenderer.invoke๋ฅผ ์ฌ์ฉํด ์ํํ ์ ์์ต๋๋ค.
์๋ ์ฝ๋๋ ์๋ฐฉํฅ ํต์ ์ ์์์ ๋๋ค.
// renderer.js
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.eletronAPI.openFile()
filePathElement.innerText = filePath
})
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('eletronAPI', {
openFile : () => ipcRenderer.invoke('dialog:openFile),
})
// main.js
const { app, BrowserWindow, ipcMain, dialog } = require("electron")
const path = require("path")
async function handleFileOpen() {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return
} else {
return filePaths[0]
}
}
function createWindow() {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
})
mainWindow.loadFile("index.html")
}
app.whenReady().then(() => {
ipcMain.handle("dialog:openFile", handleFileOpen)
createWindow()
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit()
})
3) Main to renderer example
๋ฉ์ธ ํ๋ก์ธ์ค์์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ๋ ๋ฉ์์ง๋ฅผ ๋ฐ๋ ๋ ๋๋ฌ๋ฅผ ์ง์ ํด์ผ ํฉ๋๋ค. ๋ฉ์์ง๋ WbContents ์ธ์คํด์ค๋ฅผ ํตํด renderer process๋ก ์ ์ก๋์ด์ผ ํฉ๋๋ค.
์ด WebContents ์ธ์คํด์ค์๋ ipcRenderer.send์ ๋์ผํ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ send ๋ฉ์๋๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
// main.js
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
const path = require('path')
function createWindow() {
const mainWindow = new BrowserWindow({
webPreferences : {
preload : path.join(__dirname, 'preload.js'),
},
})
const memu = Memu.buildFromTemplate([
{
label : app.name,
submenu : [
{
click : () => mainWindow.webContents.sned('update-counter', 1),
label : 'Increment',
},
{
click : () => mainWindow.webContents.send('update-counter', -1),
label : 'Decrement',
}
]
},
])
Memu.setAppicationMemu(menu)
mainWindow.loadFile('index.html')
// Open the DevTools
mainWindow.webContents.openDevTools() // ์น์ฒ๋ผ ์ฑ์์๋ ๊ฐ๋ฐ์ ์ฐฝ์ ์ด์ด์ค๋ค.
app.whenReady().then(() => {
ipcMain.on('counter-value', (_event, value) => {
console.log(value)
})
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
handlerCounter : callback => ipcRenderer.on('update-counter', callback)
})
์ฌ๊ธฐ๊น์ง, ์ฐ๋ฆฌ๊ฐ ์ผ๋ ํธ๋ก ์ ์ฌ์ฉํ ๋ ์์๋ฌ์ผ ํ ์ค์ํ ๊ฐ๋ ์ ๋ํ ์ ๋ฆฌ๋ฅผ ํ์ต๋๋ค. ๋ค์ ํฌ์คํธ์๋ React์ ํจ๊ป ์ฌ์ฉํ ์ค์ ์คํ ๊ณผ์ ์ ๋ด์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.โบ
์ถ์ฒ :
https://tech.kakao.com/2021/08/17/frontend-growth-11/
https://www.electronjs.org/docs/latest/
https://sonicce99.github.io/electron/#learning-goals-1