ํญ์ ๋ฐฐ์๋ณด๊ณ ์ถ์๋ ํ๋ก ํธ์๋ ์คํ 1์์๋ electron์ด๋ค. PWA๋ฅผ ์ฌ์ฉํ๋ฉด PC์์๋ ์ดํ๋ฆฌ์ผ์ด์ ์ฒ๋ผ ์ ์ ๊ฐ๋ฅํ์ง๋ง, ๊ทธ๋ณด๋ค๋ ๋ ๊ทผ๋ณธ์ ์ผ๋ก "PC ์ฑ"์ธ ๊ฒ์ ๋ง๋ค์ด ๋ณด๊ณ ์ถ์๊ธฐ ๋๋ฌธ์ด๋ค. Cursor IDE๋ฅผ ์ฌ์ฉํ์ฌ ๋ฝ๋ชจ๋๋ก ์ฑ์ ๊ฐ๋ฐํ๋ฉด์ ์ผ๋ ํธ๋ก ์ ์ฒดํํด๋ณด์๋ค.
0๏ธโฃElectron.js
์น ๊ธฐ์ (HTML, CSS, Javascript)์ ์ฌ์ฉํ์ฌ ํฌ๋ก์ค ํ๋ซํผ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ฐํ ์ ์๋ ์คํ ์์ค ํ๋ ์์ํฌ
์ผ๋ ํธ๋ก ์ ํต์ฌ์ Chromium(Google Chrome ์คํ ์์ค)์ Node.js๋ฅผ ํ๋์ ๋ฐํ์์ผ๋ก ํตํฉํ๋ค๋ ๊ฒ์ด๋ค. Chromium์ ์น ์ฝํ
์ธ ๋ฅผ ๋ ๋๋งํ๊ณ , Node.js๋ ํ์ผ ์์คํ
, ๋คํธ์ํฌ ๋ฑ ์์คํ
๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋ API๋ฅผ ์ ๊ณตํ๋ค. ์ด ๋ ๊ธฐ์ ์ ๊ฒฐํฉ์ผ๋ก ์น ๊ฐ๋ฐ์๋ ์ต์ํ ๊ธฐ์ ์ ํ์ฉํ๋ฉด์๋ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๊ฒ ๋์๋ค.
ํ์ฌ ์ผ๋ ํธ๋ก ์ Notion, Github Desktop, Discord, Figma ๋ฑ ๋ง์ ์ ๋ช
์ ํ๋ฆฌ์ผ์ด์
์ ๊ธฐ๋ฐ ๊ธฐ์ ๋ก ์ฌ์ฉ๋๊ณ ์๋ค. ๊พธ์คํ ๊ฐ๋ฐ๋๊ณ ์์ผ๋ฉฐ, ํ์ฌ๋ v35.x ๋ฒ์ ๊น์ง ๋ฆด๋ฆฌ์ฆ ๋์๋ค.
https://github.com/electron/electron
GitHub - electron/electron: :electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS
:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS - electron/electron
github.com
๋ฐ์คํฌํฑ ์ฑ ๊ฐ๋ฐ ๊ธฐ์ ๋ค
์ผ๋ ํธ๋ก ๋ง๊ณ ๋ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ๋ฐํ ์ ์๋ ๋ค์ํ ๊ธฐ์ ๋ค์ด ์๋ค.
1. ๋ค์ดํฐ๋ธ ๊ฐ๋ฐ(Qt, .NET, WPF, Cocoa ๋ฑ)
- ์ฅ์ : ๋ฐ์ด๋ ์ฑ๋ฅ, ๋ค์ดํฐ๋ธ, UI/UX, ์ต์ ํ๋ ๋ฆฌ์์ค ์ฌ์ฉ
- ๋จ์ : ํ๋ซํผ๋ณ ์ฝ๋๋ฒ ์ด์ค ํ์, ํ์ต ๊ณก์ ๊ฐํ๋ฆ, ๊ฐ๋ฐ ์๋ ๋๋ฆผ
2. ์๋ฐ(Java Swing, JavaFX)
- ์ฅ์ : Write once, Run anywhere", ํ๋ถํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํ๊ณ
- ๋จ์ : ๋ค์ดํฐ๋ธํ์ง ์์ UI, JVM ํ์, ํฐ ์ฉ๋
3. React Native for Windows/MacOS
- ์ฅ์ : React ๊ฐ๋ฐ์์๊ฒ ์น์, ๋ค์ดํฐ๋ธ์ ๊ฐ๊น์ด ์ฑ๋ฅ
- ๋จ์ : ์๋์ ์ผ๋ก ์๋ก์ด ๊ธฐ์ , ์ํ๊ณ๊ฐ ๋ ์ฑ์
4. NW.js(node-webkit)
- ์ฅ์ : Node.js์ Chromium ํตํฉ(์ผ๋ ํธ๋ก ๊ณผ ์ ์ฌ)
- ๋จ์ : ์ผ๋ ํธ๋ก ๋ณด๋ค ์์ ์ปค๋ฎค๋ํฐ, ์ ๋ฐ์ดํธ ์ฃผ๊ธฐ๊ฐ ๋๋ฆผ
5. Tauri
- ์ฅ์ : Rust ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ณ๊ณ ๋น ๋ฆ, ๋ณด์ ์ค์ฌ ์ค๊ณ
- ๋จ์ : ๋น๊ต์ ์๋ก์ด ํ๋ ์์ํฌ, Rust ์ง์ ํ์
ํ์ฐ๋ฆฌ๋ ์ฑ ํฌ๊ธฐ๊ฐ ์๊ณ ๋ฆฌ์์ค ์ฌ์ฉ์ด ์ ์ง๋ง, ์ผ๋ ํธ๋ก ์ด ๋ ํ๋ถํ API ์ ๊ณตํ๋ค.
6. Flutter Desktop
- ์ฅ์ : ๋จ์ผ ์ฝ๋๋ฒ ์ด์ค๋ก ๋ชจ๋ฐ์ผ, ์น, ๋ฐ์คํฌํฑ ์ง์
- ๋จ์ : Dart ์ธ์ด ํ์ต ํ์, ๋ฐ์คํฌํฑ ์ง์์ด ์์ง ๋ฐ์ ์ค
7. Electron
- ์ฅ์ : ๋ฎ์ ์ง์ ์ฅ๋ฒฝ, ํฌ๋ก์ค ํ๋ซํผ ์ง์, ํ๋ถํ ์ปค๋ฎค๋ํฐ
- ๋จ์ : ํฐ ์ฉ๋, ์๋์ ์ผ๋ก ๋๋ฆฐ ์๋, ๋ณด์์ฑ
์๋ง์ ๋ฐ์คํฌํฑ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ ๊ธฐ์ ๋ค์ด ์์ง๋ง, ๋๋ ์น ๊ฐ๋ฐ์ด ์ต์ํ๊ณ , ๋ ์ ๊ธฐ์ ๋ค๋ณด๋ค๋ ์ผ๋ ํธ๋ก ์ ๋ ์์ฃผ ์ ํ๊ธฐ์(์๋ฃ๊ฐ ๋ง์๋ณด์) ์ผ๋ ํธ๋ก ์ ๊ณต๋ถํด๋ณด๊ธฐ๋ก ๊ฒฐ์ฌํ๋ค.
1๏ธโฃElectron์ ํต์ฌ ๊ฐ๋ ๋ฐ ๊ตฌ์กฐ
์ผ๋ ํธ๋ก ์ ๋ฉํฐ ํ๋ก์ธ์ค ์ํคํ
์ฒ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ๋ ๊ฐ ํ๋ก์ธ์ค-๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ก ๊ตฌ์ฑ๋๋ค.
๋ฉ์ธ ํ๋ก์ธ์ค
๋ฉ์ธ ํ๋ก์ธ์ค๋ Node.js ํ๊ฒฝ์์ ์คํ๋๋ ์ฑ์ ํต์ฌ์ด๋ค. package.json์ main ํ๋์ ์ง์ ๋ Javascript ํ์ผ(main.js)์ด ๋ฉ์ธ ํ๋ก์ธ์ค์ ์์์ ์ด ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
๋น ํ๋์ ๋ฉ์ธ ํ๋ก์ธ์ค๋ง ์กด์ฌํ๋ค.
๋ฉ์ธ ํ๋ก์ธ์ค์ ์ฃผ์ ํน์ง:
์์คํ ๋ฆฌ์์ค ์ ๊ทผ | Node.js API๋ฅผ ํตํด ํ์ผ ์์คํ , ๋คํธ์ํฌ, OS ๊ธฐ๋ฅ ๋ฑ์ ์ง์ ์ ๊ทผํ ์ ์๋ค. |
๋ค์ดํฐ๋ธ UI ๊ด๋ฆฌ | ๋ฉ๋ด, ํธ๋ ์ด ์์ด์ฝ, ๋ํ์์ ๋ฑ OS ๋ค์ดํฐ๋ธ UI ์์๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ค. |
์ฐฝ ์์ฑ | BrowserWindow ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ์ฑ ์ฐฝ์ ๋ง๋ค๊ณ ๊ด๋ฆฌํ๋ค. |
์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ | ์ฑ์ ์์, ์ข ๋ฃ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์์ ๋ฑ์ ์ ์ดํ๋ค |
๋ ๋๋ฌ ํ๋ก์ธ์ค ์์ฑ ๋ฐ ๊ด๋ฆฌ | ๊ฐ ์ฐฝ์ ๋ํ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ฅผ ์์ฑํ๊ณ ํต์ ํ๋ค. |
๋ฉ์ธ ํ๋ก์ธ์ค๋ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ ์กฐ์ ์ ์ญํ ์ ํ๋ฉฐ, ํนํ ์์คํ
์์ค์ ์์
์ ๋ด๋นํ๋ค. ๋ฉ์ธ ํ๋ก์ธ์ค๊ฐ ์ข
๋ฃ๋๋ฉด, ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์
์ด ์ข
๋ฃ๋๋ค.
๋ ๋๋ฌ ํ๋ก์ธ์ค
๋ ๋๋ฌ ํ๋ก์ธ์ค๋ Chromium ๊ธฐ๋ฐ์ผ๋ก ์คํ๋๋ฉฐ, ๊ฐ ๋ธ๋ผ์ฐ์ ์ฐฝ๋ง๋ค ๋ณ๋์ ํ๋ก์ธ์ค๋ก ์์ฑ๋๋ค. ์ฆ, ํ๋์ ์ผ๋ ํธ๋ก ์ฑ์ ์ฌ๋ฌ ๊ฐ์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ฅผ ๊ฐ์ง ์ ์๋ค.
๋ ๋๋ฌ ํ๋ก์ธ์ค์ ์ฃผ์ ํน์ง:
์น ์ฝํ ์ธ ๋ ๋๋ง | HTML, CSS๋ฅผ ์ฌ์ฉํด UI๋ฅผ ๋ ๋๋งํ๊ณ , Javascript๋ก ๋์์ ๊ตฌํํ๋ค. |
์น ํ์ค ์ค์ | ์น ๋ธ๋ผ์ฐ์ ์ ๊ฑฐ์ ๋์ผํ๊ฒ ์น ํ์ค ๊ธฐ์ ์ ์ฌ์ฉํ ์ ์๋ค. |
๊ฒฉ๋ฆฌ๋ ํ๊ฒฝ | ๊ฐ ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ์๋ก ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๋ฉฐ, ํ ์ฐฝ์ ์ถฉ๋์ด ๋ค๋ฅธ ์ฐฝ์ ์ํฅ์ ์ฃผ์ง ์๋๋ค. |
์ ํ๋ ๊ถํ | ๊ธฐ๋ณธ์ ์ผ๋ก ์์คํ ๋ฆฌ์์ค์ ์ง์ ์ ๊ทผํ ์ ์์ผ๋ฉฐ, ๋ฉ์ธ ํ๋ก์ธ์ค๋ฅผ ํตํด ์์ฒญํด์ผ ํ๋ค. |
์น ๋ณด์ ๋ชจ๋ธ | Same-Origin Policy ๋ฑ ์น ๋ณด์ ์ ์ฑ ์ด ์ ์ฉ๋๋ค. |
๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์น ํ์ด์ง์ฒ๋ผ ๋์ํ์ง๋ง, ์ผ๋ ํธ๋ก API๋ฅผ ํตํด ์ถ๊ฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.
ํ๋ก์ธ์ค ๊ฐ ์ํธ์์ฉ
1. IPC๋ฅผ ํตํ ํต์
ํ๋ก์ธ์ค ๊ฐ ํต์ (Inter-Process Communication, IPC)์ ๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค๊ฐ ๋ฉ์์ง๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ์ฃผ์ ๋ฐฉ๋ฒ์ด๋ค. ์ผ๋ ํธ๋ก ์ ๋ ๊ฐ์ง IPC ๋ชจ๋์ ์ ๊ณตํ๋ค.
- ipcMain: ๋ฉ์ธ ํ๋ก์ธ์ค์์ ์ฌ์ฉํ๋ฉฐ, ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ์๋ตํ๋ค.
- ipcRenderer: ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ ์ฌ์ฉํ๋ฉฐ, ๋ฉ์ธ ํ๋ก์ธ์ค๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ์๋ต์ ์์ ํ๋ค.
IPC ํต์ ํจํด:
๋น๋๊ธฐ ๋จ๋ฐฉํฅ ํต์ | ipcRenderer.send(), ipcMain.on() - ๋ฉ์์ง ์์ |
์์ฒญ-์๋ต ํจํด | ipcRenderer.invoke(), ipcMain.handle() |
๋ฉ์ธ ํ๋ก์ธ์ค์์ ๋ ๋๋ฌ๋ก ๋ฉ์์ง ์ ์ก | webContents.send(), ipcRenderer.on() |
2. ์ปจํ ์คํธ ๋ธ๋ฆฟ์ง
ํ๋ ์ผ๋ ํธ๋ก ์ฑ์์๋ contextBridge๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์ธ ํ๋ก์ธ์ค์ ๊ธฐ๋ฅ์ ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ์์ ํ๊ฒ ๋
ธ์ถํ๋ค. ๋ณด์์ ๊ฐํํ๋ฉด์๋, ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ ํ์ํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋ค.
์ contextBridge๊ฐ ํ์ํ ๊น?
๊ธฐ๋ณธ์ ์ผ๋ก ๋ ๋๋ฌ ํ๋ก์ธ์ค๋ ๋ณด์์์ ์ด์ ๋ก Node.js์ ์ ๊ทผํ ์ ์๋ค. ๊ณผ๊ฑฐ์๋ nodeIntegration:true ์ต์
์ ์ฌ์ฉํ์ฌ ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ node.js API๋ฅผ ์ง์ ์ฌ์ฉํ๊ฒ ํ์ผ๋, ์ด๋ ๋ณด์์ ์ทจ์ฝ์ ์ ์ด๋ํ ์ ์๋ค. ์ด์, ๋ณด์ ๊ฐํ๋ฅผ ์ํด Node.js API ์ ๊ทผ์ ์ ํํ๋ฉด์๋ ํ์ํ ๊ธฐ๋ฅ์ ๋
ธ์ถํ๋ ๋ฐฉ๋ฒ์ผ๋ก contextBridge๊ฐ ์ฌ์ฉ๋๋ค.
โก๏ธ contextBridge๋ ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ๋ฉ์ธ ํ๋ก์ธ์ค ๊ฐ์ ์์ ํ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ์ฌ ๋ณด์์ฑ๊ณผ ๊ธฐ๋ฅ์ฑ์ ๋ชจ๋ ์ถฉ์กฑํ๋ ์ค์ํ ์ญํ ์ ํ๋ค.
์ฃผ์ ๋ชจ๋: ๋ฉ์ธ ํ๋ก์ธ์ค ๋ชจ๋
์ผ๋ ํธ๋ก ์ ๋ฐ์คํฌํฑ ์ฑ ๊ฐ๋ฐ์ ํ์ํ ๋ค์ํ ๋ชจ๋์ ์ ๊ณตํ๋ค. ๋ฝ๋ชจ๋๋ก ์ฑ ๊ฐ๋ฐ์๋ ์๋ ๋ชจ๋๋ค์ ์ฌ์ฉํ๋ค.
app ๋ชจ๋: ์ ํ๋ฆฌ์ผ์ด์
์๋ช
์ฃผ๊ธฐ ๊ด๋ฆฌ
app.whenReady(); //์ฑ ์ด๊ธฐํ๊ฐ ์๋ฃ๋๋ฉด Proimse๋ฅผ ๋ฐํ(.then์ ์ฌ์ฉํ์ฌ ํ์ ์์
ํ์)
app.on('window-all-closed'); //๋ชจ๋ ์ฐฝ์ด ๋ซํ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ
app.on('activate'); //macOS์์ ์ฑ ์์ด์ฝ์ ํด๋ฆญํ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ
app.quit(); //์ฑ์ ์์ ํ ์ข
๋ฃ
app.getPath(); //OS๋ณ ํน์ ๋๋ ํ ๋ฆฌ ๊ฒฝ๋ก ๋ฐํ(์ฌ์ฉ์ ๋ฐ์ดํฐ ํด๋ ๋ฑ)
BrowserWindow ๋ชจ๋: ๋ธ๋ผ์ฐ์ ์ฐฝ ์์ฑ, ๊ด๋ฆฌ
new BrowserWindow(options); //์ ์ฐฝ ์์ฑ, options๋ก ํฌ๊ธฐ, ๋์, ๋ชจ์ ๋ฑ ์ค์
win.loadFile(); //๋ก์ปฌ HTML ํ์ผ ๋ก๋
win.loadURL(); //์๊ฒฉ URL ๋ก๋
win.webContets(); //์ฐฝ์ ์ฝํ
์ธ ์ ์ด(๊ฐ๋ฐ์ ๋๊ตฌ ์ด๊ธฐ, ์๋ก๊ณ ์นจ ๋ฑ)
win.setAlwaysOnTop(); //์ฐฝ์ ํญ์ ์์ ํ์ํ๋๋ก ๊ณ ์
ipcMain ๋ชจ๋: ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ ํต์ ๋ด๋น
ipcMain.on(channel, listner); //๋น๋๊ธฐ ๋ฉ์์ง ์์
ipcMain.handle(channel, handler); //Promise ๊ธฐ๋ฐ ์์ฒญ ์ฒ๋ฆฌ
ipcMain.removeAllListeners(); //ํน์ ์ฑ๋์ ๋ชจ๋ ๋ฆฌ์ค๋ ์ ๊ฑฐ
Notification ๋ชจ๋: ์์คํ
์๋ฆผ ์์ฑ
new Notification(options); //์๋ฆผ ์์ฑ
notification.show(); //์๋ฆผ ํ์
notification.on('click'); //์๋ฆผ ํด๋ฆญ ์ด๋ฒคํธ ์ฒ๋ฆฌ
์ฃผ์ ๋ชจ๋: ๋ ๋๋ฌ ํ๋ก์ธ์ค ๋ชจ๋
ipcRenderer ๋ชจ๋: ๋ฉ์ธ ํ๋ก์ธ์ค์ ํต์
ipcRenderer.send(channel, ...args); //๋น๋๊ธฐ ๋ฉ์์ง ์ ์ก
ipcRenderer.invoke(channel, ...args); //Promise ๊ธฐ๋ฐ ์์ฒญ ์ ์ก
ipcRenderer.on(channel, listener); //๋ฉ์ธ ํ๋ก์ธ์ค๋ก๋ถํฐ ํน์ ์ฑ๋(channel)์ ๋ฉ์์ง๋ฅผ ์์ ํ๋ฉด ์คํ๋๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋
ipcRenderer.removeAllListeners(); //๋ฆฌ์ค๋ ์ ๊ฑฐ(ํ๋ผ๋ฏธํฐ๊ฐ ์์ผ๋ฉด ๋ชจ๋ ์ฑ๋์ ๋ฆฌ์ค๋ ์ ๊ฑฐ
contextBridge ๋ชจ๋: ์ปจํ
์คํธ ๊ฒฉ๋ฆฌ ํ๊ฒฝ์์ ์์ ํ๊ฒ API๋ฅผ ๋
ธ์ถ
contextBridge.exposeInMainWorld(apiKey, api); //๋ ๋๋ฌ ํ๋ก์ธ์ค์ API ๋
ธ์ถ
2๏ธโฃ๋ฝ๋ชจ๋๋ก ์ฑ ๊ฐ๋ฐํ๊ธฐ
1๋จ๊ณ: ๋ฉ์ธ ํ๋ก์ธ์ค
const { app, BrowserWindow, ipcMain } = require("electron");
const path = require("path");
const Store = require("electron-store");
// ๋ฐ์ดํฐ ์ ์ฅ์ ์ด๊ธฐํ
const store = new Store();
// ๋ฉ์ธ ์๋์ฐ ๊ฐ์ฒด๋ฅผ ์ ์ญ ์ฐธ์กฐ๋ก ์ ์ง
let mainWindow;
/**
* ๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
์๋์ฐ๋ฅผ ์์ฑํ๋ ํจ์
*/
function createWindow() {
// ๋ธ๋ผ์ฐ์ ์ฐฝ ์์ฑ
mainWindow = new BrowserWindow({
width: 300, // ๋ฝ๋ชจ๋๋ก ํ์ด๋จธ๋ฅผ ์ํด ํฌ๊ธฐ ์กฐ์
height: 450,
resizable: false, // ํฌ๊ธฐ ๊ณ ์
webPreferences: {
preload: path.join(__dirname, "preload.js"),
contextIsolation: true,
nodeIntegration: false,
},
});
// ์ธ๋ฑ์ค HTML ํ์ผ ๋ก๋
mainWindow.loadFile(path.join(__dirname, "renderer/index.html"));
// ๊ฐ๋ฐ ๋ชจ๋์์ ๊ฐ๋ฐ์ ๋๊ตฌ ์ด๊ธฐ
if (process.argv.includes("--dev")) {
mainWindow.webContents.openDevTools();
}
// ์ฐฝ์ด ๋ซํ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ
mainWindow.on("closed", () => {
mainWindow = null;
});
}
// Electron์ด ์ด๊ธฐํ๋ฅผ ๋ง์น๊ณ ์ค๋น๋๋ฉด ์ฐฝ ์์ฑ
app.whenReady().then(() => {
createWindow();
});
// ๋ชจ๋ ์ฐฝ์ด ๋ซํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ (macOS ์ ์ธ)
app.on("window-all-closed", () => {
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", () => {
// macOS์์๋ dock ์์ด์ฝ ํด๋ฆญ ์ ์ฐฝ์ด ์์ผ๋ฉด ๋ค์ ์ฐฝ ์์ฑ
if (mainWindow === null) {
createWindow();
}
});
- BrowserWindow ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋๋น 300, ๋์ด 450์ ๊ณ ์ ํฌ๊ธฐ ์ฐฝ์ ์์ฑํ๋ค.
- webPreferences ๊ฐ์ฒด์์ ๋ณด์ ์ค์ ์ ๊ตฌ์ฑํ๋ค.
- preload: ๋ ๋๋ฌ ํ๋ก์ธ์ค๊ฐ ๋ก๋๋๊ธฐ ์ ์ ์คํ๋ ์คํฌ๋ฆฝํธ ๊ฒฝ๋ก ์ง์
- contextIsolation: ๋ ๋๋ฌ ํ๋ก์ธ์ค์ Node.js ํ๊ฒฝ ๊ฐ์ ๋ณด์ ๊ฒฝ๊ณ ์ค์
- nodeIntegration: ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ Node.js API์ ์ง์ ์ ๊ทผ ๋ฐฉ์ง
- app.whenReady(), app.on('window-all-closed'), app.on('activate') ๋ฑ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ์ฌ์ฉํด ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
- electron-store์ ์ฌ์ฉํด ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ์ดํฐ ์ ์ฅ์ ์ด๊ธฐํ
๋ฝ๋ชจ๋๋ก ํ์ด๋จธ์ ํ์ํ ์ฐฝ์ ์์ฑํ๊ณ , ํ๋ซํผ ๋ฌด๊ด ์ผ๊ด๋ ๋์์ ์ ๊ณตํ๊ธฐ ์ํ ๊ธฐ์ด ํ์ ๋ง๋ค์๋ค.
2๋จ๊ณ: IPC ํต์ ์ผ๋ก ๋ฐ์ดํฐ ์ฃผ๊ณ ๋ฐ๊ธฐ
๋ค์์ผ๋ก, ํ์ด๋จธ ์ค์ ์ ์ ์ฅํ๊ณ ๋ถ๋ฌ์ค๋ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด IPC ํต์ ์ ์ถ๊ฐํ๋ค.
// ํ์ด๋จธ ์ค์ ๊ธฐ๋ณธ๊ฐ
const DEFAULT_TIMER_SETTINGS = {
pomodoro: 25,
shortBreak: 5,
longBreak: 15
};
// ํ์ด๋จธ ์ค์ ๋ฐ์ดํฐ
let timerSettings = store.get("timerSettings", DEFAULT_TIMER_SETTINGS);
// IPC ์ด๋ฒคํธ ๋ฆฌ์ค๋ ์ค์
// ํ์ด๋จธ ์ค์ ๊ฐ์ ธ์ค๊ธฐ
ipcMain.handle("get-timer-settings", () => {
return timerSettings;
});
// ํ์ด๋จธ ์ค์ ์
๋ฐ์ดํธ
ipcMain.handle("update-timer-settings", (event, newSettings) => {
timerSettings = { ...timerSettings, ...newSettings };
store.set("timerSettings", timerSettings);
return true;
});
- electron-store์ ์ฌ์ฉํ์ฌ ํ์ด๋จธ ์ค์ ์ ์๊ตฌ ์ ์ฅ์์ ์ ์ฅํ๊ณ ๋ถ๋ฌ์จ๋ค. ์ฌ์์ ์ ์ฌ์ฉ์ ์ค์ ์ ์ง
- ipcMain.hadle() ๋งค์๋๋ฅผ ์ฌ์ฉํ์ฌ Promise ๊ธฐ๋ฐ์ ์์ฒญ-์๋ต ํจํด์ ์ฌ์ฉํ๋ค.
- ๊ธฐ๋ณธ ํ์ด๋จธ ์ค์ ๊ฐ์ ์ ๊ณตํ๊ณ , ์ฌ์ฉ์๊ฐ ๋ณ๊ฒฝํ ์ค์ ์ ๋ฐ์ํ์ฌ ์ ์ฅํ๋ ํจํด์ ์ฌ์ฉํ๋ค.
3๋จ๊ณ: ํ๋ฆฌ๋ก๋ ์คํฌ๋ฆฝํธ์ ๋ณด์ ๋ชจ๋ธ
์ผ๋ ํธ๋ก ์ฑ์ ๋ณด์์ ๊ฐํํ๊ธฐ ์ํด ์ปจํ
์คํธ ๊ฒฉ๋ฆฌ(Context Isolation)์ ํ๋ฆฌ๋ก๋ ์คํฌ๋ฆฝํธ๋ฅผ ํ์ฉํ๋ค.
// preload.js
const { contextBridge, ipcRenderer } = require("electron");
// ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ์์ ํ๊ฒ API ๋
ธ์ถ
contextBridge.exposeInMainWorld("electronAPI", {
// ํ์ด๋จธ ์ค์ ๊ด๋ จ API
getTimerSettings: () => ipcRenderer.invoke("get-timer-settings"),
updateTimerSettings: (settings) => ipcRenderer.invoke("update-timer-settings", settings),
// ์๋ฆผ ๊ด๋ จ API
sendNotification: (title, body) => ipcRenderer.invoke("send-notification", { title, body })
});
- contextBridge.exposeInMainWorld ๋งค์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋ฌ ํ๋ก์ธ์ค์ electronAPI ๊ฐ์ฒด๋ฅผ ๋ ธ์ถํ๋ค.
- ๋ ธ์ถ๋ API๋ ๋ ๋๋ฌ ํ๋ก์ธ์ค์์ window.electronAPI๋ก ์ ๊ทผํ ์ ์๋ค.
- ๊ฐ API ๋ฉ์๋๋ ipcRenderer.invoke()๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์ธ ํ๋ก์ธ์ค์ ํต์ ํ๋ค.
- ๋ ๋๋ฌ ํ๋ก์ธ์ค๊ฐ ํ์ํ ๊ธฐ๋ฅ๋ง ์ฌ์ฉํ ์ ์๋๋ก ์ ํํ์ฌ ๋ณด์์ ๊ฐํํ๋ค.
4๋จ๊ณ: ๋ฐ์คํฌํฑ ์๋ฆผ ๊ตฌํ
์ง์ค ์๊ฐ์ด ์ข
๋ฃ๋๋ฉด, ์๋ฆผ์ด ๋จ๊ฒ ํ์๋ค.
// ์๋ฆผ ํ์
function showNotification() {
if (Notification.permission === "granted") {
const title = timerMode === "pomodoro" ? "์์
์๊ฐ ์๋ฃ!" : "ํด์ ์๊ฐ ์๋ฃ!";
const body = timerMode === "pomodoro"
? "์ ํ์
จ์ต๋๋ค! ์ด์ ํด์ํ ์๊ฐ์
๋๋ค."
: "ํด์์ด ๋๋ฌ์ต๋๋ค. ๋ค์ ์์
์ ์์ํ์ธ์.";
new Notification(title, { body });
} else if (Notification.permission !== "denied") {
Notification.requestPermission();
}
}
- Notification์ ์ฌ์ฉํ์ฌ ํ์ด๋จธ ์๋ฃ ์ ์ฌ์ฉ์์๊ฒ ์๋ฆผ์ ํ์ํ๋ค.
- ์๋ฆผ ๊ถํ ์ฌ๋ถ๋ฅผ ํ์ธํ๊ณ , ๊ถํ์ด ์๋ค๋ฉด ๊ถํ์ ์์ฒญํ๋ค.
๊ฒฐ๊ณผ


์์
์๊ฐ, ํด์ ์๊ฐ์ ์ค์ ํ ์ ์์ผ๋ฉฐ ์์
์ธ์
๋์ ์ ํ์ํ๋๋ก UI๋ฅผ ๊ตฌ์ฑํ๋ค. ์์
, ํด์์ด ๋๋๋ฉด ์๋์ฐ ์๋ฆผ์ผ๋ก ๋ฉ์์ง์ ์๋ฆผ์์ ๋์ด๋ค.
์ธ์ฌ์ดํธ & ํ๊ณ
์ด์ค ํ๋ก์ธ์ค ์ํคํ
์ฒ์ ์ดํด
์ผ๋ ํธ๋ก ์ ์ด์ค ํ๋ก์ธ์ค ์ํคํ
์ฒ๋ฅผ ์ง์ ๊ฒฝํํ๋ฉฐ ๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ์ญํ ๊ณผ ๋์์ ์ดํดํ ์ ์์๋ค. ํนํ Cursor์ ์ฌ์ฉํด ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๋ฉด์ ๋ ํ๋ก์ธ์ค ๊ฐ์ ์ฐจ์ด์ ์ํธ์์ฉ ๋ฐฉ์์ ๋น ๋ฅด๊ฒ ์ฒด๊ฐํ ์ ์์๋ค.
์ฒ์์๋ ๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค์ ๊ตฌ๋ถ, ๊ทธ๋ฆฌ๊ณ IPC ํต์ ๋ฐฉ์์ด ๋ณต์กํ๊ฒ ๋๊ปด์ก์ง๋ง, ์ฝ๋๋ฅผ ๋๋ฒ๊น
ํ๋ฉด์ ๊ตฌ์กฐ๋ฅผ ์ตํ๋ค. ๋ฉ์ธ ํ๋ก์ธ์ค๊ฐ OS ์์๊ณผ ์ง์ ์ํธ์์ฉํ๊ณ , ๋ ๋๋ฌ ํ๋ก์ธ์ค๊ฐ UI๋ฅผ ๋ด๋นํ๋ ๋ฐฉ์์ด ๋ณด์๊ณผ ์ฑ๋ฅ ์ธก๋ฉด์์ ๊ฐ์ง๋ ์ด์ ์ ์ดํดํ ์ ์์๋ค.
IPC ํต์ ํจํด
๋ฉ์ธ ํ๋ก์ธ์ค์ ๋ ๋๋ฌ ํ๋ก์ธ์ค ๊ฐ์ ํต์ ์ ์ํ ๋ค์ํ ํจํด์ ํ์ตํ๋ค. ipcMain.handle, ipcRendere.invoke๋ฅผ ํ์ฉํ Promise ๊ธฐ๋ฐ ํต์ ๋ฐฉ์ ๋ฑ, ๋ณต์กํ ๋ฐ์ดํฐ ํ๋ฆ์ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ์์ ์ตํ๋ค.
์์ฌ์ด ์
์ด๋ฒ ํ๋ก์ ํธ์์๋ ์ผ๋ ํธ๋ก ์์ฒด ๊ธฐ๋ฅ ๊ฒฝํ์ ์ง์คํ๊ธฐ ์ํด ์์ HTML, CSS, Javascript๋ฅผ ์ฌ์ฉํ๋ค. ํ์ง๋ง ๊ฐ๋ฐ์ ์งํํ๋ฉด์ UI ์ปดํฌ๋ํธ ๊ด๋ฆฌ์ ์ํ ๊ด๋ฆฌ ๋ฑ ๋ค์ํ ์ธก๋ฉด์์ ์ด๋ ค์์ ๊ฒช์๋ค. ํนํ ํ์ด๋จธ UI, ํต๊ณ ํ๋ฉด ๋ฑ์ ๊ตฌํํ๋ฉด์ React์ ๊ฐ์ ํ๋ ์์ํฌ์ ๋ถ์ฌ๊ฐ ๋ง์ด ์์ฌ์ ๋ค. ๋ํ active-win ๋ฑ, ์ฌ์ฉํ๊ณ ์ ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์จ์ ํ ํ์ฉํ์ง ๋ชปํด ๋ ์์ฌ์์ด ํฌ๋ค.
ํฅํ ๊ณํ
๋จผ์ , ์ผ๋ ํธ๋ก ๊ณต์ ๋ฌธ์๋ฅผ ํตํด ๊ธฐ๋ณธ ๊ฐ๋
์ ํํํ ๋ค์ง ์์ ์ด๋ค. ์ฑ์ ๊ฐ์ ํ ๋๋ ํ์ฑ ์ฐฝ ๊ฐ์ง์ ๊ฐ์ ๋ค์ดํฐ๋ธ ๊ธฐ๋ฅ ๊ตฌํ์ ์ง์คํ ์์ ์ด๋ค. active-win ๋ฑ ๋ค์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํด๋ณด๋ ค๊ณ ํ๋ค.
๋ํ React๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๋ค ์ฒด๊ณ์ ์ธ ๊ตฌ์กฐ๋ก ์ฑ์ ๊ฐ๋ฐํ๊ณ , ๊ธฐ๋ฅ ํ์ฅ๊ณผ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ ๋ฐฉ์์ผ๋ก ๊ฐ์ ํ๋ ค๊ณ ํ๋ค.