빠른 시작
이곳에서는 electron/electron-quick-start
와 유사하게 일렉트론에서 간단한 Hello World
앱을 만드는 과정을 안내합니다.
이 자습서를 끝까지 따라하면, 앱은 실행 중인 크로미움, 노드, 일렉트론의 버전에 대한 정보가 포함된 웹 페이지를 표시하는 브라우저 창을 열 것입니다.
준비하기
일렉트론을 사용하려면 노드를 설치해야 합니다. 가능한 최신 LTS
버전을 사용하는 것이 좋습니다.
여러분의 플랫폼에 맞는 설치 프로그램을 사용하여 노드를 설치하세요. 그렇지 않으면 다른 개발 도구와 호환되지 않는 문제가 발생할 수 있습니다.
노드가 올바르게 설치되었는지 확인하려면 터미널 클라이언트에 다음 명령을 입력하세요.
sh
node -vnpm -v
sh
node -vnpm -v
명령은 노드와 npm의 버전을 출력해야 합니다.
일렉트론은 노드를 이진에 내장하므로, 코드를 실행하는 노드의 버전은 시스템에서 실행 중인 노드의 버전과 관련이 없습니다.
애플리케이션 만들기
프로젝트의 기초 세우기
일렉트론 앱은 다른 노드 프로젝트와 동일한 일반적인 구조를 갖습니다. 폴더를 만들고 npm 패키지를 초기화하여 프로젝트를 시작하세요.
- npm
- Yarn
- pnpm
sh
mkdir my-electron-app && cd my-electron-appnpm init
sh
mkdir my-electron-app && cd my-electron-appnpm init
sh
mkdir my-electron-app && cd my-electron-appyarn init
sh
mkdir my-electron-app && cd my-electron-appyarn init
sh
mkdir my-electron-app && cd my-electron-apppnpm init
sh
mkdir my-electron-app && cd my-electron-apppnpm init
대화형 init
명령은 설정에서 일부 필드를 지정하라는 메시지를 표시합니다. 이 자습서의 목적을 위해 따라야 할 몇 가지 규칙이 있습니다.
- 진입점은
main.js
여야 합니다. author
와description
에는 아무 값이나 넣을 수 있지만 앱 패키징에 필요합니다.
package.json
파일은 다음과 같아야 합니다.
json
{"name": "my-electron-app","version": "1.0.0","description": "Hello World!","main": "main.js","author": "Jane Doe","license": "MIT"}
json
{"name": "my-electron-app","version": "1.0.0","description": "Hello World!","main": "main.js","author": "Jane Doe","license": "MIT"}
이제 electron
패키지를 앱의 devDependencies
에 설치합니다.
- npm
- Yarn
- pnpm
sh
npm install --save-dev electron
sh
npm install --save-dev electron
sh
yarn add --dev electron
sh
yarn add --dev electron
sh
pnpm add --save-dev electron
sh
pnpm add --save-dev electron
일렉트론을 설치하는 과정에서 문제가 생겼다면 고급 설치 안내서를 참고하세요.
마지막으로 일렉트론 실행을 위한 설정이 필요합니다. package.json
설정의 scripts
필드에 다음과 같이 start
명령을 추가합니다.
json
{"scripts": {"start": "electron ."}}
json
{"scripts": {"start": "electron ."}}
이 start
명령을 사용하면 개발 모드에서 앱을 열 수 있습니다.
- npm
- Yarn
- pnpm
sh
npm start
sh
npm start
sh
yarn start
sh
yarn start
sh
pnpm start
sh
pnpm start
이 스크립트는 일렉트론 프로젝트의 루트 폴더에서 실행되도록 지시합니다. 이 단계의 앱에서는 실행할 앱을 찾을 수 없다는 오류가 바로 발생합니다.
주 프로세스 실행하기
일렉트론 애플리케이션의 진입점은 main
스크립트입니다. 이 스크립트는 전체 노드 환경에서 실행됩니다. 스크립트는 앱의 수명 주기를 제어하고, 네이티브 인터페이스를 표시하고, 권한 있는 작업을 수행하고, 렌더러 프로세스를 관리하는 주 프로세스(main process)를 제어합니다. (자세한 내용은 나중에 설명함)
실행 중에 일렉트론은 앱의 기초 세우기 단계에서 설정했던 package.json
의 main
필드의 값을 이용하여 스크립트를 찾습니다.
main
스크립트를 초기화하려면 프로젝트의 루트 폴더에 main.js
라는 빈 파일을 만드세요.
이 시점에서 start
스크립트를 다시 실행하면 앱에서 더 이상 오류가 발생하지 않습니다! 그러나 아직 main.js
에 코드를 추가하지 않았기 때문에 아무 작업도 수행하지 않습니다.
웹 페이지 만들기
앱 창을 만들기 전에 창에 로드할 콘텐츠를 만들어야 합니다. 일렉트론에서 각 창은 로컬 HTML 파일 또는 원격 URL에서 로드할 수 있는 웹 콘텐츠를 표시합니다.
이 자습서에서는 로컬 HTML 파일을 사용합니다. 프로젝트의 루트 폴더에 다음 index.html
파일을 만드세요.
html
<!DOCTYPE html><html><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self'"/><title>Hello World!</title></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.</body></html>
html
<!DOCTYPE html><html><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self'"/><title>Hello World!</title></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.</body></html>
이 HTML 문서를 보면 본문의 텍스트에 버전 값이 누락된 것을 확인할 수 있습니다. 나중에 자바스크립트를 사용하여 수동으로 삽입할 것입니다.
브라우저 창에서 웹 페이지 열기
이제 웹 페이지가 생겼으니 앱 창에 로드해 보겠습니다. 여기에는 두 개의 일렉트론 모듈이 필요합니다.
- 앱의 이벤트 수명 주기를 제어하는
app
모듈 - 앱 창을 만들고 관리하는
BrowserWindow
모듈
주 프로세스는 노드를 실행하므로 파일의 맨 위에서 코먼JS 모듈로 가져오는 것이 가능합니다.
js
const { app, BrowserWindow } = require('electron');
js
const { app, BrowserWindow } = require('electron');
그런 다음 index.html
을 새로운 BrowserWindow
인스턴스로 로드하는 createWindow()
함수를 추가합니다.
js
const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,});win.loadFile('index.html');};
js
const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,});win.loadFile('index.html');};
이제 이 createWindow()
함수를 호출하여 창을 엽니다.
일렉트론에서 브라우저 창은 app
모듈의 ready
이벤트가 발생한 후에만 생성할 수 있습니다. app.whenReady()
API를 사용하여 이 이벤트를 기다릴 수 있습니다. whenReady()
가 프라미스를 이행한 후 createWindow()
를 호출합니다.
js
app.whenReady().then(() => {createWindow();});
js
app.whenReady().then(() => {createWindow();});
이 시점에서 일렉트론 앱은 웹 페이지를 표시하는 창을 성공적으로 열어야 합니다!
창의 수명 주기 관리하기
이제 브라우저 창을 열 수 있습니다. 하지만 각 플랫폼에 더 네이티브한 느낌을 주려면 몇 가지 상용구 코드가 추가로 필요합니다. 앱 창은 각 OS에서 다르게 작동하며, 일렉트론은 이러한 규칙을 앱에 구현할 책임을 개발자에게 부여합니다.
일반적으로 전역 process
의 platform
프로퍼티를 사용하여 특정 운영 체제용 코드를 실행할 수 있습니다.
모든 창이 닫힐 때 앱 종료하기 (윈도우 및 리눅스)
윈도우와 리눅스에서 모든 창을 종료하면 일반적으로 앱이 완전히 종료됩니다.
이를 구현하려면, app
모듈의 'window-all-closed'
이벤트를 수신하고, 사용자가 맥OS(darwin
)를 사용하지 않는다면 app.quit()
를 호출합니다.
js
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit();});
js
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit();});
열려 있는 창이 없으면 창 열기 (맥OS)
리눅스와 윈도우 앱은 열려 있는 창이 없을 때 종료됩니다. 반면 맥OS 앱은 일반적으로 창이 열려 있지 않아도 계속 실행되며, 사용 가능한 창이 없을 때 앱을 활성화하면 새 창이 열립니다.
이 기능을 구현하려면, app
모듈의 activate
이벤트를 수신하고, 브라우저 창이 열려 있지 않으면 기존의 createWindow()
메서드를 호출합니다.
ready
이벤트 전에는 창을 만들 수 없으므로, 앱이 초기화된 후에만 activate
이벤트를 수신해야 합니다. 이를 위해서는 기존의 whenReady()
콜백 내에서 이벤트 수신기를 연결하면 됩니다.
js
app.whenReady().then(() => {createWindow();app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow();});});
js
app.whenReady().then(() => {createWindow();app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow();});});
이 시점에서 창 조작이 완전히 작동해야 합니다!
사전 로드 스크립트를 사용하여 렌더러에서 노드에 접근하기
이제 마지막으로 할 일은 일렉트론의 버전 번호와 종속성을 웹 페이지에 출력하는 것입니다.
이 정보에 접근하는 것은 노드의 전역 process
객체를 통해 주 프로세스에서 간단하게 수행할 수 있습니다. 그러나 주 프로세서에서 렌더러의 document
컨텍스트에 접근할 수는 없기 때문에, DOM을 편집할 수는 없습니다. 그들은 완전히 다른 프로세스에 있습니다!
일렉트론의 프로세스에 대해 더 자세히 살펴보려면 프로세스 모델 문서를 참고하세요.
이때 렌더러에 사전 로드(preload) 스크립트를 첨부하는 것이 편리합니다. 사전 로드 스크립트는 렌더러 프로세스가 로드되기 전에 실행되며 렌더러 전역(예: window
및 document
)과 노드 환경에 모두 접근할 수 있습니다.
다음과 같이 preload.js
라는 새 스크립트를 만드세요.
js
window.addEventListener('DOMContentLoaded', () => {const replaceText = (selector, text) => {const element = document.getElementById(selector);if (element) element.innerText = text;};for (const dependency of ['chrome', 'node', 'electron']) {replaceText(`${dependency}-version`, process.versions[dependency]);}});
js
window.addEventListener('DOMContentLoaded', () => {const replaceText = (selector, text) => {const element = document.getElementById(selector);if (element) element.innerText = text;};for (const dependency of ['chrome', 'node', 'electron']) {replaceText(`${dependency}-version`, process.versions[dependency]);}});
이 코드는 노드의 process.versions
객체에 접근하고, 기본적인 replaceText
도우미 함수를 실행하여 버전 번호를 HTML 문서에 삽입합니다.
이 스크립트를 렌더러 프로세스에 첨부하려면, 사전 로드 스크립트의 경로를 기존 BrowserWindow
생성자의 webPreferences.preload
옵션에 전달합니다.
js
// 파일 상단에 노드의 path 모듈을 포함합니다.const path = require('path');// 기존의 createWindow() 함수를 수정합니다.const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),},});win.loadFile('index.html');};// ...
js
// 파일 상단에 노드의 path 모듈을 포함합니다.const path = require('path');// 기존의 createWindow() 함수를 수정합니다.const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),},});win.loadFile('index.html');};// ...
여기에 사용되는 노드 개념이 두 가지 있습니다.
__dirname
문자열은 현재 실행 중인 스크립트의 경로(이 경우 프로젝트의 루트 폴더)를 가리킵니다.path.join
API는 여러 경로 조각을 결합하여 모든 플랫폼에서 작동하는 결합된 경로 문자열을 생성합니다.
현재 실행 중인 자바스크립트 파일에 상대적인 경로를 사용하므로, 개발 모드와 패키지 모드 모두에서 상대 경로가 작동합니다.
보너스: 웹 콘텐츠에 기능 추가하기
이 시점에서 애플리케이션에 더 많은 기능을 추가하는 방법이 궁금할 수 있습니다.
웹 콘텐츠와의 상호 작용을 위해 렌더러 프로세스에 스크립트를 추가하려고 합니다. 렌더러는 보통의 웹 환경에서 실행되기 때문에, index.html
파일의 닫는 </body>
태그 바로 앞에 <script>
태그를 추가하여 원하는 스크립트를 넣을 수 있습니다.
html
<script src="./renderer.js"></script>
html
<script src="./renderer.js"></script>
renderer.js
에 포함된 코드는 일반적인 프런트엔드 개발에 사용하는 것과 동일한 자바스크립트 API 및 도구를 사용할 수 있습니다. 예를 들어 웹팩을 사용하여 코드를 묶고 축소하거나, 리액트를 사용하여 사용자 인터페이스를 관리할 수 있습니다.
요약
위의 단계를 따른 후에는 일렉트론 애플리케이션이 다음과 같이 완전히 작동해야 합니다.
전체 코드는 다음과 같습니다.
main.jsjs
// 앱의 수명을 제어하고 기본 브라우저 창을 만드는 모듈입니다.const { app, BrowserWindow } = require('electron');const path = require('path');const createWindow = () => {// 브라우저 창을 만듭니다.const mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),},});// 그리고 앱의 'index.html'을 로드합니다.mainWindow.loadFile('index.html');// 개발도구를 엽니다.// mainWindow.webContents.openDevTools()};// 이 메서드는 일렉트론이 초기화를 완료하고 브라우저 창을 생성할 준비가 되면 호출됩니다.// 일부 API는 이 이벤트가 발생한 후에만 사용할 수 있습니다.app.whenReady().then(() => {createWindow();app.on('activate', () => {// 맥OS에서는 독 아이콘을 클릭하고 열려 있는 다른 창이 없을 때// 앱에서 창을 다시 만드는 것이 일반적입니다.if (BrowserWindow.getAllWindows().length === 0) createWindow();});});// 맥OS가 아닐 때 모든 창이 닫히면 종료합니다.// 이 경우에는 사용자가 'Cmd + Q'로 명시적으로 종료할 때까지// 앱과 해당 메뉴 표시줄이 활성 상태로 유지되는 것이 일반적입니다.app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit();});// 이 파일에는 앱의 특정한 주 프로세스 코드의 나머지 부분이 포함될 수 있습니다. 코드를 별도의 파일에 넣고 여기에서 요구(require)할 수도 있습니다.
main.jsjs
// 앱의 수명을 제어하고 기본 브라우저 창을 만드는 모듈입니다.const { app, BrowserWindow } = require('electron');const path = require('path');const createWindow = () => {// 브라우저 창을 만듭니다.const mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, 'preload.js'),},});// 그리고 앱의 'index.html'을 로드합니다.mainWindow.loadFile('index.html');// 개발도구를 엽니다.// mainWindow.webContents.openDevTools()};// 이 메서드는 일렉트론이 초기화를 완료하고 브라우저 창을 생성할 준비가 되면 호출됩니다.// 일부 API는 이 이벤트가 발생한 후에만 사용할 수 있습니다.app.whenReady().then(() => {createWindow();app.on('activate', () => {// 맥OS에서는 독 아이콘을 클릭하고 열려 있는 다른 창이 없을 때// 앱에서 창을 다시 만드는 것이 일반적입니다.if (BrowserWindow.getAllWindows().length === 0) createWindow();});});// 맥OS가 아닐 때 모든 창이 닫히면 종료합니다.// 이 경우에는 사용자가 'Cmd + Q'로 명시적으로 종료할 때까지// 앱과 해당 메뉴 표시줄이 활성 상태로 유지되는 것이 일반적입니다.app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit();});// 이 파일에는 앱의 특정한 주 프로세스 코드의 나머지 부분이 포함될 수 있습니다. 코드를 별도의 파일에 넣고 여기에서 요구(require)할 수도 있습니다.
preload.jsjs
// 사전 로드 프로세스에서 모든 노드 API를 사용할 수 있습니다.// 크롬 확장 프로그램과 동일한 샌드박스를 가지고 있습니다.window.addEventListener('DOMContentLoaded', () => {const replaceText = (selector, text) => {const element = document.getElementById(selector);if (element) element.innerText = text;};for (const dependency of ['chrome', 'node', 'electron']) {replaceText(`${dependency}-version`, process.versions[dependency]);}});
preload.jsjs
// 사전 로드 프로세스에서 모든 노드 API를 사용할 수 있습니다.// 크롬 확장 프로그램과 동일한 샌드박스를 가지고 있습니다.window.addEventListener('DOMContentLoaded', () => {const replaceText = (selector, text) => {const element = document.getElementById(selector);if (element) element.innerText = text;};for (const dependency of ['chrome', 'node', 'electron']) {replaceText(`${dependency}-version`, process.versions[dependency]);}});
index.htmlhtml
<!DOCTYPE html><html><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self'"/><title>Hello World!</title></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.<!-- 이 프로세스에서 다른 파일을 실행하도록 요구할 수도 있습니다. --><script src="./renderer.js"></script></body></html>
피들에서 열기index.htmlhtml
<!DOCTYPE html><html><head><meta charset="UTF-8" /><!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --><metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self'"/><title>Hello World!</title></head><body><h1>Hello World!</h1>We are using Node.js <span id="node-version"></span>, Chromium<span id="chrome-version"></span>, and Electron<span id="electron-version"></span>.<!-- 이 프로세스에서 다른 파일을 실행하도록 요구할 수도 있습니다. --><script src="./renderer.js"></script></body></html>
수행한 모든 단계를 요약하면 다음과 같습니다.
- 노드 앱을 부트스트랩하고 일렉트론을 종속성으로 추가했습니다.
- 앱을 제어하고 노드 환경에서 실행되는 주 프로세스를 실행하는
main.js
스크립트를 만들었습니다. 이 스크립트에서는 일렉트론의app
과BrowserWindow
모듈을 사용하여 별도의 프로세스(렌더러)에서 웹 콘텐츠를 표시하는 브라우저 창을 만들었습니다. - 렌더러에서 특정 노드 기능에 접근하기 위해
BrowserWindow
생성자에 사전 로드 스크립트를 첨부했습니다.
애플리케이션 패키징과 배포
새로 만든 앱을 배포하는 가장 빠른 방법은 일렉트론 포지를 사용하는 것입니다.
먼저 일렉트론 포지를 앱의 개발 종속성으로 추가하고 import
명령을 사용하여 포지의 기초 세우기를 설정합니다.
- npm
- Yarn
- pnpm
sh
npm install --save-dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
sh
npm install --save-dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
sh
yarn add --dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
sh
yarn add --dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
sh
pnpm add --save-dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
sh
pnpm add --save-dev @electron-forge/clinpx electron-forge import✔ Checking your system✔ Initializing Git Repository✔ Writing modified package.json file✔ Installing dependencies✔ Writing modified package.json file✔ Fixing .gitignoreWe have ATTEMPTED to convert your app to be in a format that electron-forge understands.Thanks for using "electron-forge"!!!
그런 다음 포지의 make
명령을 사용하여 배포 파일을 만듭니다.
- npm
- Yarn
- pnpm
sh
npm run make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
sh
npm run make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
sh
yarn make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
sh
yarn make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
sh
pnpm run make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
sh
pnpm run make> my-electron-app@1.0.0 make /my-electron-app> electron-forge make✔ Checking your system✔ Resolving Forge ConfigWe need to package your application before we can make it✔ Preparing to Package Application for arch: x64✔ Preparing native dependencies✔ Packaging ApplicationMaking for the following targets: zip✔ Making for target: zip - On platform: darwin - For arch: x64
일렉트론 포지는 패키지가 위치할 out
폴더를 생성합니다.
// 맥OS의 예시out/├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip├── ...└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app
// 맥OS의 예시out/├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip├── ...└── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app