├── .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 | [![Mentioned in Awesome Electron](https://awesome.re/mentioned-badge.svg)](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 | ![](https://github.com/ccnokes/build-a-desktop-app-with-electron/raw/master/images/egghead-electron-logo.png) 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 | --------------------------------------------------------------------------------