├── .gitignore
├── 01-hello-world
├── index.html
├── index.js
└── package.json
├── 02-load-css
├── index.html
├── main.js
├── package.json
├── renderer.js
└── style.css
├── 03-load-js
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 04-menu
├── index.html
├── main-menu.js
├── main.js
└── package.json
├── 05-06-dialogs
├── dialogs.js
├── index.html
├── kitten.jpeg
├── main-menu.js
├── main.js
└── package.json
├── 07-main-renderer
├── counter.js
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 08-ipc
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 09-remote
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 10-app-icon
├── build-assets
│ └── icon.png
├── build
│ ├── icon.icns
│ └── icon.ico
├── main.js
├── package.json
└── renderer.js
├── 11-package
├── build-assets
│ └── icon.png
├── build
│ ├── icon.icns
│ └── icon.ico
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 12-codesign
├── build-assets
│ ├── build-mac.sh
│ ├── build-win.cmd
│ ├── icon.png
│ ├── verify-mac.sh
│ └── verify-win.cmd
├── build
│ ├── icon.icns
│ └── icon.ico
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 13-autoupdates-mac
├── auto-updater.js
├── build-assets
│ ├── build-mac.sh
│ ├── build-win.cmd
│ └── icon.png
├── build
│ ├── icon.icns
│ └── icon.ico
├── index.html
├── main.js
├── package.json
└── renderer.js
├── 14-autoupdates-win
├── auto-updater.js
├── build-assets
│ ├── build-mac.sh
│ ├── build-win.cmd
│ └── icon.png
├── build
│ ├── icon.icns
│ └── icon.ico
├── index.html
├── main.js
├── package.json
└── renderer.js
├── README.md
├── bin
└── symlink.js
├── images
└── egghead-electron-logo.png
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 | dist
4 | *.p12
5 | *.pfx
6 | *.log
7 | *.zip
8 | *.app
9 | *.dmg
--------------------------------------------------------------------------------
/01-hello-world/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World!
4 |
5 |
6 |
7 | Hello World!
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/01-hello-world/index.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 |
5 | app.on('ready', () => {
6 | mainWindow = new BrowserWindow();
7 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
8 | });
9 |
--------------------------------------------------------------------------------
/01-hello-world/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hello-world",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "devDependencies": {
7 | "electron": "^1.6.6"
8 | },
9 | "scripts": {
10 | "start": "electron index.js"
11 | },
12 | "keywords": [],
13 | "author": "Cameron Nokes",
14 | "license": "ISC"
15 | }
16 |
--------------------------------------------------------------------------------
/02-load-css/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Egghead Electron Course
4 |
5 |
6 |
7 |
8 |
9 | You are running Electron version:
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/02-load-css/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 |
5 | app.on('ready', () => {
6 | mainWindow = new BrowserWindow({
7 | show: false
8 | });
9 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
10 | mainWindow.on('ready-to-show', () => {
11 | mainWindow.show();
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/02-load-css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "load-css",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/02-load-css/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = process.versions.electron;
3 | console.log(process.versions);
4 |
--------------------------------------------------------------------------------
/02-load-css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 |
6 | color: #333;
7 | font-family: 'Open Sans', sans-serif;
8 | text-align: center;
9 | }
10 |
--------------------------------------------------------------------------------
/03-load-js/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Egghead Electron Course
4 |
5 |
6 |
7 |
8 | You are running Electron version:
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/03-load-js/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 |
5 | app.on('ready', () => {
6 | mainWindow = new BrowserWindow();
7 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
8 | });
9 |
--------------------------------------------------------------------------------
/03-load-js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "load-js",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/03-load-js/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = process.versions.electron;
3 | console.log(process.versions);
4 |
--------------------------------------------------------------------------------
/04-menu/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Menus
4 |
12 |
13 |
14 | Native menus in Electron
15 |
16 |
17 |
--------------------------------------------------------------------------------
/04-menu/main-menu.js:
--------------------------------------------------------------------------------
1 | const { app, Menu } = require('electron');
2 | const isWindows = process.platform === 'win32';
3 |
4 | module.exports = {
5 | setMainMenu
6 | };
7 |
8 | function setMainMenu() {
9 | const template = [
10 | {
11 | label: isWindows ? 'File' : app.getName(),
12 | submenu: [
13 | {
14 | label: isWindows ? 'Exit' : `Quit ${app.getName()}`,
15 | accelerator: isWindows ? null : 'CmdOrCtrl+Q',
16 | click() {
17 | app.quit();
18 | }
19 | }
20 | ]
21 | },
22 | {
23 | label: 'Edit',
24 | submenu: [
25 | { role: 'undo' },
26 | { role: 'redo' },
27 | { type: 'separator' }, //just adds a line visually
28 | { role: 'cut' },
29 | { role: 'copy' },
30 | { role: 'paste' },
31 | { role: 'selectall' }
32 | ]
33 | }
34 | ];
35 | const menu = Menu.buildFromTemplate(template);
36 | Menu.setApplicationMenu(menu);
37 | }
--------------------------------------------------------------------------------
/04-menu/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 | const { setMainMenu } = require('./main-menu');
5 |
6 | app.on('ready', () => {
7 | mainWindow = new BrowserWindow({
8 | show: false
9 | });
10 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
11 | mainWindow.on('ready-to-show', () => {
12 | mainWindow.show();
13 | });
14 | setMainMenu();
15 | });
16 |
--------------------------------------------------------------------------------
/04-menu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "menus",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/05-06-dialogs/dialogs.js:
--------------------------------------------------------------------------------
1 | const { dialog, app, nativeImage } = require('electron');
2 | const fs = require('fs');
3 | const path = require('path');
4 |
5 | module.exports = { showMessage, showSaveDialog, showOpenDialog };
6 |
7 |
8 | function showMessage(browserWindow) {
9 | dialog.showMessageBox(browserWindow, {
10 | type: 'info', //Windows sets different icons depending on this (if icon is unset)
11 | icon: nativeImage.createFromPath('./kitten.jpeg'), //ignored on Windows
12 | // title: 'Hello', //this isn't shown on MacOS, but is on Windows. If blank, it's your app name on Windows
13 | message: 'Hello',
14 | detail: 'Just a friendly meow.',
15 | buttons: ['Meow', 'Close'], //can pass multiple buttons in here and then get the index of the clicked on in the callback
16 | defaultId: 0
17 | }, (clickedIndex) => {
18 | console.log(clickedIndex);
19 | });
20 | }
21 |
22 | function showSaveDialog(browserWindow) {
23 | dialog.showSaveDialog(browserWindow, {
24 | defaultPath: path.join(app.getPath('downloads'), 'memory-info.txt')
25 | }, (filename) => {
26 | if(filename) {
27 | const memInfo = JSON.stringify(process.getProcessMemoryInfo(), null, 2);
28 | fs.writeFile(filename, memInfo, 'utf8', (err) => {
29 | if(err) {
30 | dialog.showErrorBox('Save failed.', err.message);
31 | }
32 | });
33 | }
34 | });
35 | }
36 |
37 | function showOpenDialog(browserWindow) {
38 | dialog.showOpenDialog(browserWindow, {
39 | defaultPath: app.getPath('downloads'),
40 | filters: [ {name: 'Text Files', extensions: ['txt']} ] //"Text Files" displays on Windows in lower right, but not on Mac
41 | }, (filepaths) => {
42 | if(filepaths) {
43 | console.log(filepaths, fs.readFileSync(filepaths[0], 'utf8'));
44 | }
45 | });
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/05-06-dialogs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Dialogs
4 |
9 |
10 |
11 | Native dialogs in Electron
12 |
13 |
--------------------------------------------------------------------------------
/05-06-dialogs/kitten.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/05-06-dialogs/kitten.jpeg
--------------------------------------------------------------------------------
/05-06-dialogs/main-menu.js:
--------------------------------------------------------------------------------
1 | const { app, Menu, BrowserWindow } = require('electron');
2 | const { showMessage, showSaveDialog, showOpenDialog } = require('./dialogs');
3 |
4 | module.exports = {
5 | setMainMenu
6 | };
7 |
8 | function setMainMenu(mainWindow) {
9 | const template = [
10 | {
11 | label: app.getName(),
12 | submenu: [
13 | {
14 | label: 'Say Hello',
15 | click() {
16 | showMessage(mainWindow);
17 | }
18 | },
19 | {
20 | label: 'Save Memory Usage Info',
21 | click() {
22 | showSaveDialog(mainWindow);
23 | }
24 | },
25 | {
26 | label: 'Open File',
27 | click() {
28 | showOpenDialog(mainWindow);
29 | }
30 | },
31 | { type: 'separator' },
32 | { role: 'quit' }
33 | ]
34 | }
35 | ];
36 | const menu = Menu.buildFromTemplate(template);
37 | Menu.setApplicationMenu(menu);
38 | }
--------------------------------------------------------------------------------
/05-06-dialogs/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 | const { setMainMenu } = require('./main-menu');
5 |
6 | app.on('ready', () => {
7 | mainWindow = new BrowserWindow();
8 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
9 | setMainMenu(mainWindow);
10 | });
11 |
--------------------------------------------------------------------------------
/05-06-dialogs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dialogs",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/07-main-renderer/counter.js:
--------------------------------------------------------------------------------
1 | const { EventEmitter } = require('events');
2 |
3 | const events = new EventEmitter();
4 | let count = 0;
5 |
6 | module.exports = {
7 | increment() {
8 | count++;
9 | events.emit('incremented', { count });
10 | },
11 | onIncremented(fn) {
12 | events.on('incremented', fn);
13 | }
14 | };
--------------------------------------------------------------------------------
/07-main-renderer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Processes
4 |
10 |
11 |
12 |
13 | My process id is:
14 |
15 | 0
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/07-main-renderer/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let windows = [];
4 |
5 | function createWindow() {
6 | const win = new BrowserWindow({ height: 300, width: 400 });
7 | win.loadURL(path.join('file://', __dirname, 'index.html'));
8 | windows.push(win);
9 | }
10 |
11 | app.on('ready', () => {
12 | createWindow();
13 | createWindow();
14 | });
15 |
--------------------------------------------------------------------------------
/07-main-renderer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "processes",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/07-main-renderer/renderer.js:
--------------------------------------------------------------------------------
1 | const counter = require('./counter');
2 |
3 | const countEl = document.querySelector('#count');
4 | const countBtn = document.querySelector('#countBtn');
5 | const pidEl = document.querySelector('#pid');
6 |
7 | pidEl.textContent = process.pid;
8 |
9 | counter.onIncremented(({count}) => {
10 | countEl.textContent = count;
11 | });
12 |
13 | countBtn.addEventListener('click', () => {
14 | counter.increment();
15 | });
16 |
--------------------------------------------------------------------------------
/08-ipc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | IPC
4 |
10 |
11 |
12 | Inter-process Communication
13 |
14 |
15 | Number of windows:
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/08-ipc/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, ipcMain } = require('electron');
2 | const path = require('path');
3 | const windows = [];
4 |
5 | function createBrowserWindow(browserWindowOpts) {
6 | let win = new BrowserWindow(Object.assign({
7 | width: 400,
8 | height: 300
9 | }, browserWindowOpts));
10 |
11 | windows.push(win);
12 | win.loadURL(path.join('file://', __dirname, 'index.html'));
13 |
14 | win.on('close', () => {
15 | windows.splice(windows.indexOf(win), 1);
16 | sendWindowCount();
17 | });
18 | }
19 |
20 | function sendWindowCount() {
21 | windows.forEach(win => {
22 | win.webContents.send('window-count', { count: windows.length });
23 | });
24 | }
25 |
26 | app.on('ready', () => {
27 | ipcMain.on('create-window', (event, props) => createBrowserWindow(props));
28 | ipcMain.on('get-window-count', sendWindowCount);
29 | createBrowserWindow();
30 | });
31 |
--------------------------------------------------------------------------------
/08-ipc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ipc",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/08-ipc/renderer.js:
--------------------------------------------------------------------------------
1 | const { ipcRenderer } = require('electron');
2 | const countEl = document.querySelector('#count');
3 |
4 | ipcRenderer.on('window-count', (event, props) => {
5 | countEl.textContent = props.count;
6 | });
7 |
8 | ipcRenderer.send('get-window-count');
9 |
10 | document.querySelector('#new-window').addEventListener('click', () => {
11 | ipcRenderer.send('create-window', {
12 | x: 0,
13 | y: 0
14 | });
15 | });
--------------------------------------------------------------------------------
/09-remote/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Remote
4 |
9 |
10 |
11 | Remote
12 |
13 |
14 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/09-remote/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 |
5 | app.on('ready', () => {
6 | mainWindow = new BrowserWindow({
7 | height: 400,
8 | width: 400
9 | });
10 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
11 | mainWindow.webContents.openDevTools();
12 | });
13 |
--------------------------------------------------------------------------------
/09-remote/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "remote",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron main.js"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron": "^1.6.6"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/09-remote/renderer.js:
--------------------------------------------------------------------------------
1 | const { remote } = require('electron');
2 | const path = require('path');
3 | require('devtron').install();
4 | let currentWindow = remote.getCurrentWindow();
5 |
6 |
7 | document.querySelector('#new-window').addEventListener('click', () => {
8 | const win = new remote.BrowserWindow({
9 | height: 400,
10 | width: 400
11 | });
12 | win.loadURL(path.join('file://', __dirname, 'index.html'));
13 | });
14 |
15 | function onBlur() {
16 | document.body.style = 'opacity: 0.2';
17 | }
18 |
19 | function onFocus() {
20 | document.body.style = 'opacity: 1';
21 | }
22 |
23 | currentWindow.on('blur', onBlur);
24 | currentWindow.on('focus', onFocus);
25 |
26 | window.addEventListener('beforeunload', () => {
27 | currentWindow.removeListener('focus', onFocus);
28 | currentWindow.removeListener('blur', onBlur);
29 | });
30 |
--------------------------------------------------------------------------------
/10-app-icon/build-assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/10-app-icon/build-assets/icon.png
--------------------------------------------------------------------------------
/10-app-icon/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/10-app-icon/build/icon.icns
--------------------------------------------------------------------------------
/10-app-icon/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/10-app-icon/build/icon.ico
--------------------------------------------------------------------------------
/10-app-icon/main.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/10-app-icon/main.js
--------------------------------------------------------------------------------
/10-app-icon/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "app-icon",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "make-icon": "electron-icon-maker -i build-assets/icon.png -o build"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "devDependencies": {
13 | "electron-icon-maker": "0.0.3"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/10-app-icon/renderer.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/10-app-icon/renderer.js
--------------------------------------------------------------------------------
/11-package/build-assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/11-package/build-assets/icon.png
--------------------------------------------------------------------------------
/11-package/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/11-package/build/icon.icns
--------------------------------------------------------------------------------
/11-package/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/11-package/build/icon.ico
--------------------------------------------------------------------------------
/11-package/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Package
4 |
15 |
16 |
17 |
18 |
19 | You are running Electron version:
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/11-package/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, Menu, dialog } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 | const isWindows = process.platform === 'win32';
5 |
6 | app.on('ready', () => {
7 | mainWindow = new BrowserWindow({
8 | show: false
9 | });
10 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
11 | mainWindow.on('ready-to-show', () => {
12 | mainWindow.show();
13 | });
14 |
15 | const menu = Menu.buildFromTemplate([
16 | {
17 | label: isWindows ? 'File' : app.getName(),
18 | submenu: [
19 | {
20 | label: isWindows ? 'Exit' : `Quit ${app.getName()}`,
21 | accelerator: isWindows ? null : 'CmdOrCtrl+Q',
22 | click() {
23 | app.quit();
24 | }
25 | },
26 | {
27 | label: 'Say Hello',
28 | click() {
29 | dialog.showMessageBox(mainWindow, {
30 | type: 'info',
31 | message: 'Hello',
32 | detail: 'Just a friendly meow.',
33 | buttons: ['Meow', 'Close'], //can pass multiple buttons in here and then get the index of the clicked on in the callback
34 | defaultId: 0
35 | });
36 | }
37 | }
38 | ]
39 | },
40 | ]);
41 | Menu.setApplicationMenu(menu);
42 | });
43 |
--------------------------------------------------------------------------------
/11-package/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "package",
3 | "productName": "HelloWorld",
4 | "author": "Cameron Nokes",
5 | "version": "1.0.0",
6 | "description": "Electron app demonstrating electron-builder",
7 | "main": "main.js",
8 | "scripts": {
9 | "start": "electron main.js",
10 | "package": "build"
11 | },
12 | "keywords": [],
13 | "license": "ISC",
14 | "devDependencies": {
15 | "electron": "^1.6.6",
16 | "electron-builder": "17.3.1"
17 | },
18 | "build": {
19 | "files": "!build-assets${/*}",
20 | "appId": "com.Egghead.HelloWorld"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/11-package/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = process.versions.electron;
--------------------------------------------------------------------------------
/12-codesign/build-assets/build-mac.sh:
--------------------------------------------------------------------------------
1 | # NB: for security reasons, the actual cert files have been omitted from this repository
2 | export CSC_LINK="$(pwd)/build-assets/mac-cert.p12"
3 | export CSC_KEY_PASSWORD="password"
4 |
5 | npm run package
--------------------------------------------------------------------------------
/12-codesign/build-assets/build-win.cmd:
--------------------------------------------------------------------------------
1 | set CSC_LINK=%cd%\build-assets\win-cert.pfx
2 | set CSC_KEY_PASSWORD=password
3 |
4 | call npm run package
--------------------------------------------------------------------------------
/12-codesign/build-assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/12-codesign/build-assets/icon.png
--------------------------------------------------------------------------------
/12-codesign/build-assets/verify-mac.sh:
--------------------------------------------------------------------------------
1 | codesign --verify --verbose --deep --strict dist/mac/Hello\ World.app
--------------------------------------------------------------------------------
/12-codesign/build-assets/verify-win.cmd:
--------------------------------------------------------------------------------
1 | REM (this is a bonus, not covered in the video)
2 | REM instructions for installing signtool.exe: https://msdn.microsoft.com/en-us/library/windows/desktop/aa387764(v=vs.85).aspx
3 | REM docs for it: https://msdn.microsoft.com/en-us/library/windows/desktop/aa388171(v=vs.85).aspx
4 |
5 | signtool.exe verify dist/win-x64\HelloWorld.exe
--------------------------------------------------------------------------------
/12-codesign/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/12-codesign/build/icon.icns
--------------------------------------------------------------------------------
/12-codesign/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/12-codesign/build/icon.ico
--------------------------------------------------------------------------------
/12-codesign/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
15 |
16 |
17 |
18 |
19 | You are running Electron version:
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/12-codesign/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, Menu, dialog } = require('electron');
2 | const path = require('path');
3 | let mainWindow;
4 | const isWindows = process.platform === 'win32';
5 |
6 | app.on('ready', () => {
7 | mainWindow = new BrowserWindow({
8 | show: false
9 | });
10 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
11 | mainWindow.on('ready-to-show', () => {
12 | mainWindow.show();
13 | });
14 |
15 | const menu = Menu.buildFromTemplate([
16 | {
17 | label: isWindows ? 'File' : app.getName(),
18 | submenu: [
19 | {
20 | label: isWindows ? 'Exit' : `Quit ${app.getName()}`,
21 | accelerator: isWindows ? null : 'CmdOrCtrl+Q',
22 | click() {
23 | app.quit();
24 | }
25 | },
26 | {
27 | label: 'Say Hello',
28 | click() {
29 | dialog.showMessageBox(mainWindow, {
30 | type: 'info',
31 | message: 'Hello',
32 | detail: 'Just a friendly meow.',
33 | buttons: ['Meow', 'Close'], //can pass multiple buttons in here and then get the index of the clicked on in the callback
34 | defaultId: 0
35 | });
36 | }
37 | }
38 | ]
39 | },
40 | ]);
41 | Menu.setApplicationMenu(menu);
42 | });
43 |
44 | app.on('window-all-closed', () => {
45 | if(process.platform !== 'darwin') {
46 | app.quit();
47 | }
48 | });
--------------------------------------------------------------------------------
/12-codesign/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "codesign",
3 | "productName": "Hello World",
4 | "author": "Cameron Nokes",
5 | "version": "1.0.0",
6 | "description": "Electron app demonstrating electron-builder with codesigning",
7 | "main": "main.js",
8 | "scripts": {
9 | "start": "electron main.js",
10 | "package": "build"
11 | },
12 | "keywords": [],
13 | "license": "ISC",
14 | "devDependencies": {
15 | "electron": "^1.6.6",
16 | "electron-builder": "17.3.1"
17 | },
18 | "build": {
19 | "files": "!build-assets${/*}",
20 | "appId": "com.Egghead.HelloWorld",
21 | "forceCodeSigning": true
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/12-codesign/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = process.versions.electron;
--------------------------------------------------------------------------------
/13-autoupdates-mac/auto-updater.js:
--------------------------------------------------------------------------------
1 | const { autoUpdater, dialog } = require('electron');
2 | const axios = require('axios');
3 | const semver = require('semver');
4 | const { version } = require('./package.json');
5 |
6 | const isMac = process.platform === 'darwin';
7 | const updateURL = 'http://localhost:8080' + (isMac ? '/mac.json' : '');
8 | // Check for flag passed to process. --dev is passed in the npm start script.
9 | const isDev = process.argv.some(str => str === '--dev');
10 |
11 | module.exports = {
12 | init
13 | };
14 |
15 | function init() {
16 | // Can't run this in development because there's no code sign in dev.
17 | if(isDev) {
18 | return;
19 | }
20 |
21 | // Do some logging on each of the events
22 | logEvents();
23 |
24 | autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateUrl) => {
25 | promptUpdate();
26 | });
27 |
28 | autoUpdater.setFeedURL(updateURL); //this also "starts" the autoUpdater
29 | checkForUpdate();
30 | }
31 |
32 | function logEvents() {
33 | autoUpdater.on('checking-for-update', () => {
34 | console.log('checking-for-update');
35 | });
36 |
37 | autoUpdater.on('update-available', () => {
38 | console.log('update-available');
39 | });
40 |
41 | autoUpdater.on('update-not-available', () => {
42 | console.log('update-not-available');
43 | });
44 |
45 | autoUpdater.on('update-downloaded', () => {
46 | console.log('update-downloaded');
47 | });
48 |
49 | autoUpdater.on('error', () => {
50 | console.error('error');
51 | });
52 | }
53 |
54 | function checkForUpdate() {
55 | // Windows updates work right out of the box
56 | if (process.platform === 'win32') {
57 | autoUpdater.checkForUpdates();
58 | } else {
59 | // For Mac, manually check if there's a version available to download. Because we're using
60 | // a simple file server for mac updates, not the HTTP 200 status = update, 204 = no update thing,
61 | // which requires some server side configuration.
62 | checkForMacUpdate().then(hasUpdate => {
63 | if(hasUpdate) {
64 | autoUpdater.checkForUpdates();
65 | }
66 | });
67 | }
68 | }
69 |
70 | function checkForMacUpdate() {
71 | return axios.get(updateURL).then(response => {
72 | // Must be a 200 response (204s = no update, technically) and
73 | // remote version must be greater than local
74 | return response.status === 200
75 | && semver.gt(response.data.version, version);
76 | }).catch(console.error);
77 | }
78 |
79 | function promptUpdate() {
80 | dialog.showMessageBox({
81 | type: 'info',
82 | message: 'Update Available',
83 | buttons: ['Update', 'Close'],
84 | defaultId: 0
85 | }, (clickedIndex) => {
86 | if(clickedIndex === 0) {
87 | // This will install and then restart the app automatically.
88 | // If the user dismisses this, the app will be auto-updated next time
89 | // they restart.
90 | autoUpdater.quitAndInstall();
91 | }
92 | });
93 | }
94 |
--------------------------------------------------------------------------------
/13-autoupdates-mac/build-assets/build-mac.sh:
--------------------------------------------------------------------------------
1 | export CSC_LINK="$(pwd)/build-assets/mac-cert.p12"
2 | export CSC_KEY_PASSWORD="password"
3 |
4 | npm run package
--------------------------------------------------------------------------------
/13-autoupdates-mac/build-assets/build-win.cmd:
--------------------------------------------------------------------------------
1 | set CSC_LINK=%cd%\build-assets\win-cert.pfx
2 | set CSC_KEY_PASSWORD=password
3 |
4 | call npm run package
--------------------------------------------------------------------------------
/13-autoupdates-mac/build-assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/13-autoupdates-mac/build-assets/icon.png
--------------------------------------------------------------------------------
/13-autoupdates-mac/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/13-autoupdates-mac/build/icon.icns
--------------------------------------------------------------------------------
/13-autoupdates-mac/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/13-autoupdates-mac/build/icon.ico
--------------------------------------------------------------------------------
/13-autoupdates-mac/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
15 |
16 |
17 |
18 |
19 | App version:
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/13-autoupdates-mac/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, Menu, dialog } = require('electron');
2 | const updater = require('./auto-updater');
3 | const path = require('path');
4 |
5 | const isWindows = process.platform === 'win32';
6 | let mainWindow;
7 |
8 | app.on('ready', () => {
9 | mainWindow = new BrowserWindow({
10 | show: false
11 | });
12 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
13 | mainWindow.on('ready-to-show', () => {
14 | mainWindow.show();
15 | });
16 |
17 | const menu = Menu.buildFromTemplate([
18 | {
19 | label: isWindows ? 'File' : app.getName(),
20 | submenu: [
21 | {
22 | label: isWindows ? 'Exit' : `Quit ${app.getName()}`,
23 | accelerator: isWindows ? null : 'CmdOrCtrl+Q',
24 | click() {
25 | app.quit();
26 | }
27 | }
28 | ]
29 | },
30 | ]);
31 | Menu.setApplicationMenu(menu);
32 |
33 | updater.init();
34 | });
35 |
36 | app.on('window-all-closed', () => {
37 | if(isWindows) {
38 | app.quit();
39 | }
40 | });
41 |
--------------------------------------------------------------------------------
/13-autoupdates-mac/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "autoupdates",
3 | "productName": "HelloWorld",
4 | "author": "Cameron Nokes",
5 | "version": "1.0.0",
6 | "description": "Electron app demonstrating auto updating",
7 | "main": "main.js",
8 | "scripts": {
9 | "start": "electron main.js --dev",
10 | "package": "build"
11 | },
12 | "keywords": [],
13 | "license": "ISC",
14 | "devDependencies": {
15 | "electron": "^1.6.6",
16 | "electron-builder": "17.3.1"
17 | },
18 | "dependencies": {
19 | "axios": "^0.16.1",
20 | "semver": "^5.3.0"
21 | },
22 | "build": {
23 | "files": "!build-assets${/*}",
24 | "appId": "com.Egghead.HelloWorld",
25 | "forceCodeSigning": true
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/13-autoupdates-mac/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = require('./package.json').version;
--------------------------------------------------------------------------------
/14-autoupdates-win/auto-updater.js:
--------------------------------------------------------------------------------
1 | const { autoUpdater, dialog } = require('electron');
2 | const axios = require('axios');
3 | const semver = require('semver');
4 | const { version } = require('./package.json');
5 |
6 | const isMac = process.platform === 'darwin';
7 | const updateURL = 'http://localhost:8080' + (isMac ? '/mac.json' : '');
8 | // Check for flag passed to process. --dev is passed in the npm start script.
9 | const isDev = process.argv.some(str => str === '--dev');
10 |
11 | module.exports = {
12 | init
13 | };
14 |
15 | function init() {
16 | // Can't run this in development because there's no code sign in dev.
17 | if(isDev) {
18 | return;
19 | }
20 |
21 | // Do some logging on each of the events
22 | logEvents();
23 |
24 | autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate, updateUrl) => {
25 | promptUpdate();
26 | });
27 |
28 | autoUpdater.setFeedURL(updateURL); //this also "starts" the autoUpdater
29 | checkForUpdate();
30 | }
31 |
32 | function logEvents() {
33 | autoUpdater.on('checking-for-update', () => {
34 | console.log('checking-for-update');
35 | });
36 |
37 | autoUpdater.on('update-available', () => {
38 | console.log('update-available');
39 | });
40 |
41 | autoUpdater.on('update-not-available', () => {
42 | console.log('update-not-available');
43 | });
44 |
45 | autoUpdater.on('update-downloaded', () => {
46 | console.log('update-downloaded');
47 | });
48 |
49 | autoUpdater.on('error', () => {
50 | console.error('error');
51 | });
52 | }
53 |
54 | function checkForUpdate() {
55 | // Windows updates work right out of the box
56 | if (process.platform === 'win32') {
57 | autoUpdater.checkForUpdates();
58 | } else {
59 | // For Mac, manually check if there's a version available to download. Because we're using
60 | // a simple file server for mac updates, not the HTTP 200 status = update, 204 = no update thing,
61 | // which requires some server side configuration.
62 | checkForMacUpdate().then(hasUpdate => {
63 | if(hasUpdate) {
64 | autoUpdater.checkForUpdates();
65 | }
66 | });
67 | }
68 | }
69 |
70 | function checkForMacUpdate() {
71 | return axios.get(updateURL).then(response => {
72 | // Must be a 200 response (204s = no update, technically) and
73 | // remote version must be greater than local
74 | return response.status === 200
75 | && semver.gt(response.data.version, version);
76 | }).catch(console.error);
77 | }
78 |
79 | function promptUpdate() {
80 | dialog.showMessageBox({
81 | type: 'info',
82 | message: 'Update Available',
83 | buttons: ['Update', 'Close'],
84 | defaultId: 0
85 | }, (clickedIndex) => {
86 | if(clickedIndex === 0) {
87 | // This will install and then restart the app automatically.
88 | // If the user dismisses this, the app will be auto-updated next time
89 | // they restart.
90 | autoUpdater.quitAndInstall();
91 | }
92 | });
93 | }
94 |
--------------------------------------------------------------------------------
/14-autoupdates-win/build-assets/build-mac.sh:
--------------------------------------------------------------------------------
1 | export CSC_LINK="$(pwd)/build-assets/mac-cert.p12"
2 | export CSC_KEY_PASSWORD="password"
3 |
4 | npm run package
--------------------------------------------------------------------------------
/14-autoupdates-win/build-assets/build-win.cmd:
--------------------------------------------------------------------------------
1 | set CSC_LINK=%cd%\build-assets\win-cert.pfx
2 | set CSC_KEY_PASSWORD=password
3 |
4 | call npm run package
--------------------------------------------------------------------------------
/14-autoupdates-win/build-assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/14-autoupdates-win/build-assets/icon.png
--------------------------------------------------------------------------------
/14-autoupdates-win/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/14-autoupdates-win/build/icon.icns
--------------------------------------------------------------------------------
/14-autoupdates-win/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/14-autoupdates-win/build/icon.ico
--------------------------------------------------------------------------------
/14-autoupdates-win/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World
4 |
15 |
16 |
17 |
18 |
19 | App version:
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/14-autoupdates-win/main.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow, Menu, dialog } = require('electron');
2 | const updater = require('./auto-updater');
3 | const path = require('path');
4 |
5 | const isWindows = process.platform === 'win32';
6 | let mainWindow;
7 |
8 | // handle Squirrel Windows startup stuff
9 | if(require('electron-squirrel-startup')) {
10 | app.quit();
11 | }
12 |
13 | if(isWindows) {
14 | // Set our AppUserModelId so Squirrel can handle our app's shortcut
15 | app.setAppUserModelId('com.squirrel.Egghead.HelloWorld');
16 | }
17 |
18 | app.on('ready', () => {
19 | mainWindow = new BrowserWindow({
20 | show: false
21 | });
22 | mainWindow.loadURL(path.join('file://', __dirname, 'index.html'));
23 | mainWindow.on('ready-to-show', () => {
24 | mainWindow.show();
25 | });
26 |
27 | const menu = Menu.buildFromTemplate([
28 | {
29 | label: isWindows ? 'File' : app.getName(),
30 | submenu: [
31 | {
32 | label: isWindows ? 'Exit' : `Quit ${app.getName()}`,
33 | accelerator: isWindows ? null : 'CmdOrCtrl+Q',
34 | click() {
35 | app.quit();
36 | }
37 | }
38 | ]
39 | },
40 | ]);
41 | Menu.setApplicationMenu(menu);
42 |
43 | updater.init();
44 | });
45 |
46 | app.on('window-all-closed', () => {
47 | if(isWindows) {
48 | app.quit();
49 | }
50 | });
51 |
--------------------------------------------------------------------------------
/14-autoupdates-win/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "autoupdates",
3 | "productName": "HelloWorld",
4 | "author": "Cameron Nokes",
5 | "version": "1.0.0",
6 | "description": "Electron app demonstrating auto updating",
7 | "main": "main.js",
8 | "scripts": {
9 | "start": "electron main.js --dev",
10 | "package": "build"
11 | },
12 | "keywords": [],
13 | "license": "ISC",
14 | "devDependencies": {
15 | "electron": "^1.6.6",
16 | "electron-builder": "17.3.1",
17 | "electron-builder-squirrel-windows": "^18.3.0"
18 | },
19 | "dependencies": {
20 | "axios": "^0.16.1",
21 | "electron-squirrel-startup": "^1.0.0",
22 | "semver": "^5.3.0"
23 | },
24 | "build": {
25 | "files": "!build-assets${/*}",
26 | "appId": "com.Egghead.HelloWorld",
27 | "forceCodeSigning": true,
28 | "squirrelWindows": {
29 | "iconUrl": "https://cameronnokes.com/egghead.ico"
30 | },
31 | "win": {
32 | "target": ["squirrel"]
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/14-autoupdates-win/renderer.js:
--------------------------------------------------------------------------------
1 | const versionEl = document.querySelector('#version');
2 | versionEl.innerText = require('./package.json').version;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Build a desktop application with Electron
2 |
3 | [](https://github.com/sindresorhus/awesome-electron#videos)
4 |
5 |
6 | This is the GitHub repo to accompany the Egghead Course "Build a desktop application with Electron". Watch it on [egghead.io](https://egghead.io/courses/build-a-desktop-application-with-electron).
7 |
8 | 
9 |
10 | ---
11 |
12 | Electron is a framework that makes it easy to create cross-platform desktop apps with JavaScript, HTML, and CSS. Electron and open-source tools give you everything you need to create a compelling desktop app--native user interface elements like menus and dialogs, installers, auto-updates, and more.
13 | This course will teach you the core concepts of Electron so that you can leverage it to create your own desktop application for macOS and Windows.
14 |
15 | We'll go over:
16 | - Creating user interfaces in Electron (both HTML based and native)
17 | - Understanding Electron's multi-process architecture
18 | - Shipping your app to users
19 |
20 | # Lessons
21 | 1. [Create a "Hello World" app using Electron](https://egghead.io/lessons/javascript-create-a-hello-world-app-using-electron)
22 |
23 | 2. [Load CSS in a Electron BrowserWindow](https://egghead.io/lessons/javascript-load-css-in-a-electron-browserwindow)
24 |
25 | 3. [Load JavaScript in an Electron BrowserWindow](https://egghead.io/lessons/javascript-load-javascript-in-an-electron-browserwindow)
26 |
27 | 4. [Create a native desktop system menu with the Electron Menu module](https://egghead.io/lessons/javascript-create-a-native-desktop-system-menu-with-the-electron-menu-module)
28 |
29 | 5. [Display native desktop dialog windows with Electron](https://egghead.io/lessons/javascript-display-native-desktop-dialog-windows-with-electron)
30 |
31 | 6. [Save/Open a file with an Electron dialog window](https://egghead.io/lessons/javascript-save-open-a-file-with-an-electron-dialog-window)
32 |
33 | 7. [Understand Electron’s main and renderer process architecture](https://egghead.io/lessons/javascript-understand-electron-s-main-and-renderer-process-architecture)
34 |
35 | 8. [Communicate between Electron processes using IPC](https://egghead.io/lessons/javascript-communicate-between-electron-processes-using-ipc)
36 |
37 | 9. [Communicate between Electron processes using the remote module](https://egghead.io/lessons/javascript-communicate-between-electron-processes-using-the-remote-module)
38 |
39 | 10. [Create an icon for your Electron app](https://egghead.io/lessons/javascript-create-an-icon-for-your-electron-app)
40 |
41 | 11. [Package your Electron application into a executable file with electron-builder](https://egghead.io/lessons/javascript-package-your-electron-application-into-a-executable-file-with-electron-builder)
42 |
43 | 12. [Code sign your Electron application with electron-builder](https://egghead.io/lessons/javascript-code-sign-your-electron-application-with-electron-builder)
44 |
45 | 13. [Ship updates to your Electron app with autoUpdater (Mac)](https://egghead.io/lessons/javascript-ship-updates-to-your-electron-app-with-autoupdater-mac)
46 |
47 | 14. [Ship updates to your Electron app with autoUpdater (Windows)](https://egghead.io/lessons/javascript-ship-updates-to-your-electron-app-with-autoupdater-windows)
48 |
49 | ---
50 |
51 | ## Usage
52 | ```
53 | git clone https://github.com/ccnokes/build-a-desktop-app-with-electron.git
54 | ```
55 |
56 | If you want to run each example, you may want to save disk space by symlinking the node_modules at the root of the project to each lesson. To do so:
57 |
58 | ```
59 | npm install
60 | npm run symlink
61 | ```
62 |
--------------------------------------------------------------------------------
/bin/symlink.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const root = path.join(__dirname, '../');
4 |
5 | // run it relative to the root of the project
6 | process.chdir(root);
7 |
8 | function symlinkAll() {
9 | const lessons = fs.readdirSync(root)
10 | .filter(f => !/images|bin|node_modules|\.git.*|.*\.md|.*\.json|\.DS_Store|.*\.log/.test(f))
11 | .forEach(f => {
12 | console.log(`Symlinking ${f}`);
13 | fs.symlink('../node_modules', `${f}/node_modules`, 'junction', (err) => {
14 | if(err) {
15 | console.error(err);
16 | }
17 | });
18 | });
19 | }
20 |
21 | symlinkAll();
22 |
--------------------------------------------------------------------------------
/images/egghead-electron-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ccnokes/build-a-desktop-app-with-electron/cec5acc41ce27519c4a9eefd39f8231ce3f1de10/images/egghead-electron-logo.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "build-desktop-application-electron",
3 | "version": "1.0.0",
4 | "description": "This is the GitHub repo to accompany the Egghead Course \"Build a desktop application with Electron\". Watch it on [egghead.io](https://egghead.io/courses/build-a-desktop-application-with-electron).",
5 | "main": "index.js",
6 | "scripts": {
7 | "symlink": "node bin/symlink.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/ccnokes/build-a-desktop-app-with-electron.git"
12 | },
13 | "keywords": [],
14 | "author": "Cameron Nokes",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/ccnokes/build-a-desktop-app-with-electron/issues"
18 | },
19 | "homepage": "https://github.com/ccnokes/build-a-desktop-app-with-electron#readme",
20 | "dependencies": {
21 | "axios": "^0.16.1",
22 | "electron-squirrel-startup": "^1.0.0",
23 | "semver": "^5.3.0"
24 | },
25 | "devDependencies": {
26 | "devtron": "^1.4.0",
27 | "electron": "^1.6.10",
28 | "electron-builder": "^18.6.2",
29 | "electron-icon-maker": "0.0.3"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------