Chapter 2. Your first Electron application
Listing 2.1. Adding a start script to package.json
Listing 2.2. Adding a basic main process: ./app/main.js
Listing 2.3. Requiring the BrowserWindow module: ./app/main.js
Listing 2.4. Creating a BrowserWindow: ./app/main.js
Listing 2.5. Creating index.html: ./app/index.html
Listing 2.6. Loading an HTML document into the main window: ./app/main.js
Listing 2.7. Adding a button to an HTML document: ./app/index.html
Listing 2.8. Adding script with Node.js global in the browser context: ./app/index.html
Listing 2.9. Loading JavaScript from renderer.js: ./app/index.html
Listing 2.10. Adding basic styles: ./app/style.css
Listing 2.11. Referencing a stylesheet in the HTML document: ./app/index.html
Listing 2.12. Adding the markup for the UI of the application: ./app/index.html
Listing 2.13. Caching DOM element selectors: ./app/renderer.js
Listing 2.14. Adding an event listener to enable the submit button: ./app/renderer.js
Listing 2.15. Adding a helper function to clear out form input: ./app/renderer.js
Listing 2.16. Adding an event listener to the submit button: ./app/renderer.js
Listing 2.17. Using the Fetch API to request a remote resource: ./app/renderer.js
Listing 2.18. Instantiating a DOMParser: ./app/renderer.js
Listing 2.19. Adding functions for parsing response and finding the title: ./app/renderer.js
Listing 2.20. Parsing response and finding the title when fetching a page: ./app/renderer.js
Listing 2.21. Current contents of app/renderer.js
Listing 2.22. Creating a function to persist links in local storage: ./app/renderer.js
Listing 2.23. Storing a link and clearing the form upon fetching remote resource: ./app/renderer.js
Listing 2.24. Creating a function for getting links from local storage: ./app/renderer.js
Listing 2.25. Creating a function for creating DOM nodes from link data: ./app/renderer.js
Listing 2.26. Creating a function to render all links and add them to the DOM: ./app/renderer.js
Listing 2.27. Rendering links after fetching a remote resource: ./app/renderer.js
Listing 2.28. Loading and rendering links: ./app/render.js
Listing 2.29. Wiring the Clear Storage button: ./app/renderer.js
Listing 2.30. Renderering process to fetch, store, and render links: ./app/renderer.js
Listing 2.31. Displaying an error message: ./app/renderer.js
Listing 2.32. Catching errors when fetching, parsing, and rendering links: ./app/renderer.js
Listing 2.33. Validating responses from remote servers: ./app/renderer.js
Listing 2.34. Adding validateResponse() to the chain: ./app/renderer.js
Listing 2.35. Requiring Electron’s shell module: ./app/renderer.js
Listing 2.36. Opening links in the user’s default browser: /app/renderer.js
Chapter 3. Building a notes application
Listing 3.1. Generating the application’s file structure
Listing 3.2. Bootstrapping the main process: ./app/main.js
Listing 3.3. Our application’s markup: ./app/index.html
Listing 3.4. Using Flexbox to create page layouts: ./app/style.css
Listing 3.5. Gracefully showing the window when the DOM’s ready: ./app/main.js
Listing 3.6. Requiring our dependencies: ./app/renderer.js
Listing 3.7. Caching DOM selectors: ./app/renderer.js
Listing 3.8. Converting Markdown to HTML: ./app/renderer.js
Listing 3.9. Re-rendering the HTML when Markdown changes: ./app/renderer.js
Listing 3.10. The renderer process: ./app/renderer.js
Listing 3.11. Opening the Developer Tools from the main process: ./app/main.js
Listing 3.12. Setting up a build task in Visual Studio Code for Windows: tasks.json
Listing 3.13. Setting up a launch task for Visual Studio Code for Windows: launch.json
Chapter 4. Using native file dialog boxes and facilitating interprocess communication
Listing 4.1. Importing the dialog module: ./app/main.js
Listing 4.2. Creating a getFileFromUser() function: ./app/main.js
Listing 4.3. Invoking getFileFromUser() when the application is first ready
Listing 4.4. Importing Node’s fs module: ./app/main.js
Listing 4.5. Whitelisting specific file types: ./app/main.js
Listing 4.6. Creating sheet dialogs in macOS: ./app/main.js
Listing 4.7. Adding an event listener in the renderer process: ./app/renderer.js
Listing 4.8. Exporting a function in Node: basic-math.js
Listing 4.9. Importing a function in Node
Listing 4.10. Exporting ability to open the file dialog from the renderer process: ./app/main.js
Listing 4.11. Requiring functions from the main process in the renderer process: ./app/renderer.js
Listing 4.12. Triggering getFileFromUser() in the main process from the UI: ./app/renderer.js
Listing 4.13. Sending content from the main to a renderer process: ./app/main.js
Listing 4.14. Importing the ipcRenderer module: ./app/renderer.js
Listing 4.15. Listening for messages on the file-opened channel: ./app/renderer.js
Listing 4.16. Open File functionality implemented in the main process: ./app/main.js
Listing 4.17. Open File functionality implemented: ./app/renderer.js
Chapter 5. Working with multiple windows
Listing 5.1. Creating a Set to keep track of new windows: ./app/main.js
Listing 5.2. Implementing a function to create new windows: ./app/main.js
Listing 5.3. Creating a window when the application is ready: ./app/main.js
Listing 5.4. Refactoring getFileFromUser() to work with a specific window: ./app/main.js
Listing 5.5. Refactoring openFile() to work with a specific window: ./app/main.js
Listing 5.6. Getting a reference to the current window in the renderer process: ./app/renderer.js
Listing 5.7. Passing a reference to the current window to the main process: ./app/renderer.js
Listing 5.8. Adding listener to newFileButton: ./app/renderer.js
Listing 5.9. newFileButton implemented in the renderer process: ./app/renderer.js
Listing 5.10. Offsetting new windows based on the currently focused window: ./app/main.js
Listing 5.11. Keeping the application alive when all windows are closed: ./app/main.js
Listing 5.12. Creating a window when application is opened and there are no windows: ./app/main.js
Listing 5.13. Multiple windows implemented in the main process: ./app/main.js
Chapter 6. Working with files
Listing 6.1. Declaring global variables for keeping track of the current file: ./app/renderer.js
Listing 6.2. Updating global variables when a new file is opened: ./app/renderer.js
Listing 6.3. Updating the window title based on the current file: ./app/renderer.js
Listing 6.4. Calling updateUserInterface() when a new file is opened: ./app/renderer.js
Listing 6.5. Updating the UI if the document has unsaved changes: ./app/renderer.js
Listing 6.6. Checking for changes whenever the user types: ./app/renderer.js
Listing 6.7. Enabling the Save and Revert buttons when there are unsaved changes: ./app/renderer.js
Listing 6.8. Setting the represented file in macOS: ./app/main.js
Listing 6.9. Appending to the list of recent documents: ./app/main.js
Listing 6.10. Responding to external requests to open a file: ./app/main.js
Listing 6.11. Saving the generated output: ./app/main.js
Listing 6.12. Triggering the Save File dialog box from the renderer process: ./app/renderer.js
Listing 6.13. Saving the current file: ./app/main.js
Listing 6.14. Adding an event listener to the Save File button: ./app/renderer.js
Listing 6.15. Reverting content in UI to last saved content: ./app/renderer.js
Listing 6.16. Setting up foundation for drag-and-drop events: ./app/renderer.js
Listing 6.17. Adding styles for drag-and-drop functionality: ./app/style.css
Listing 6.18. Helper methods: ./app/renderer.js
Listing 6.19. Adding and removing classes on dragover and dragleave: ./app/renderer.js
Listing 6.20. Drag-and-drop functionality: ./app/renderer.js
Listing 6.21. Setting up a Map to watch files: ./app/main.js
Listing 6.22. Setting up a listener: ./app/main.js
Listing 6.23. Closing the watcher when the browser window closes: ./app/main.js
Listing 6.24. Prompting the user if they try to close a window with unsaved changes: ./app/main.js
Listing 6.25. Refactoring the process of displaying a new file: ./app/renderer.js
Listing 6.27. Prompting the user when a file changes: ./app/renderer.js
Listing 6.28. Sending a message over the file-changed channel: ./app/main.js
Chapter 7. Building application and context menus
Listing 7.1. Creating an Edit menu with copy and paste: ./app/application-menu.js
Listing 7.2. Loading the menu in the main application file: ./app/main.js
Listing 7.3. Prepending to the list of menu items in macOS: ./app/application-menu.js
Listing 7.4. Edit menu template: ./app/application-menu.js
Listing 7.5. Using roles and accelerators: ./app/application-menu.js
Listing 7.6. Application menu for macOS: ./app/application-menu.js
Listing 7.7. Combining the application, Edit, and Window menus: ./app/application-menu.js
Listing 7.8. Creating a Help menu: ./app/application-menu.js
Listing 7.9. Custom menu functionality: ./app/application-menu.js
Listing 7.10. Add IPC listeners to the renderer process: ./app/renderer.js
Listing 7.13. Listening for contextmenu events: ./app/renderer.js
Listing 7.14. Creating a context menu: ./app/renderer.js
Listing 7.15. Triggering the context menu: ./app/renderer.js
Chapter 8. Further operating system integration and dynamically enabling menu items
Listing 8.1. Enabling the buttons when there is a file to show: ./app/renderer.js
Listing 8.2. Adding event listeners to the buttons: ./app/renderer.js
Listing 8.3. Adding additional menu items: ./app/application-menu
Listing 8.5. Adding shell module access to the context menu template: ./app/renderer.js
Listing 8.6. Creating a function to dynamically create context menus: ./app/renderer.js
Listing 8.7. Converting values into Booleans
Listing 8.8. Creating a context menu each time a contextmenu event is fired: ./app/renderer.js
Listing 8.10. Setting the represented file: ./app/main.js
Listing 8.11. Generating a new application menu when state might have changed: ./app/main.js
Chapter 9. Introducing the tray module
Listing 9.1. Creating a tray instance: ./app/main.js
Listing 9.2. Hiding the dock icon on macOS: ./app/main.js
Listing 9.3. Conditionally choosing an icon based on the platform: ./app/main.js
Listing 9.4. Supporting dark mode on macOS: ./app/main.js
Listing 9.5. Storing clippings in memory using an array: ./app/main.js
Listing 9.6. Adding a clipping to the array when the menu item is clicked: ./app/main.js
Listing 9.7. Listing out the clippings as menu items: ./app/main.js
Listing 9.8. Truncating menu item labels: ./main/app.js
Listing 9.9. Preventing duplicate clippings: ./app/main.js
Listing 9.10. Adding clippings to the beginning of the array: ./main.js
Listing 9.11. Displaying only the first 10 clippings: ./app/main.js
Listing 9.12. Registering a global shortcut: ./app/main.js
Listing 9.13. Setting up a simple HTML document: ./app/index.html
Listing 9.14. Listening for messages and displaying notifications: ./app/renderer.js
Listing 9.15. Launching the hidden browser window: ./app/main.js
Listing 9.16. Sending a message to the renderer process: ./app/main.js
Listing 9.17. Setting an alternate icon for when icon is pressed: ./app/main.js
Listing 9.18. Clipmaster’s completed main process: ./app/main.js
Listing 9.19. Clipmaster’s completed renderer process: ./app/renderer.js
Chapter 10. Building applications with the menubar library
Listing 10.1. Getting started with menubar: ./app/main.js
Listing 10.2. The markup for the UI: ./app/index.html
Listing 10.3. Styling for the UI: ./app/style.css
Listing 10.4. Loading the HTML page after a window has been created: ./app/main.js
Listing 10.5. Querying for and caching frequently used selectors: ./app/renderer.js
Listing 10.6. Creating an element for the UI based on the clipping’s text: ./app/renderer.js
Listing 10.7. Reading from clipboard and adding a clipping to list: ./app/renderer.js
Listing 10.8. Setting up an event listener for each clipping’s buttons: ./app/renderer.js
Listing 10.9. Removing a clipping from the DOM: ./app/renderer.js
Listing 10.10. Configuring the event listener to remove clippings: ./app/renderer.js
Listing 10.11. Setting up helper methods for working with clippings: ./app/renderer.js
Listing 10.12. Configuring the event listener to display the clipping’s text: ./app/renderer.js
Listing 10.13. Refactoring the removeClipping() function: ./app/renderer.js
Listing 10.14. Creating a function to write a clipping to the clipboard: ./app/renderer.js
Listing 10.15. Adding writeToClipboard() to the event listener: ./app/renderer.js
Listing 10.16. Requiring and configuring default parameters for request: ./app/renderer.js
Listing 10.17. Creating a function to publish a clipping to ClipHub’s API: ./app/renderer.js
Listing 10.18. Adding publishClipping() to the event listener: ./app/renderer.js
Listing 10.19. Setting up notifications when publishing a clipping: ./app/renderer.js
Listing 10.20. Setting up a simple global shortcut: ./app/main.js
Listing 10.21. Setting up global shortcuts with IPC: ./app/main.js
Listing 10.22. Setting up IPC listeners in the renderer process: ./app/renderer.js
Listing 10.23. Preloading window and contents on start-up: ./app/main.js
Chapter 11. Using transpilers and frameworks
Listing 11.1. Configuring Babel for use with electron-compile: ./.compilerc
Listing 11.2. The renderer process’s HTML file written in Jade: ./app/index.jade
Listing 11.3. Application styles using Sass: ./app/style.scss
Listing 11.4. The main process for Jetsetter: ./app/main.js
Listing 11.5. A simple component using JSX and React: ./app/renderer.js
Listing 11.6. The Application component after transpilation
Listing 11.7. Application component foundation: ./app/components/Application.js
Listing 11.8. Mounting the new Application component onto the DOM: ./app/renderer.js
Listing 11.9. Individual Item component: ./app/components/Item.js
Listing 11.10. Item list component: ./app/components/Items.js
Listing 11.11. Item and Items in the Application component: ./app/components/Application.js
Listing 11.12. Adding a NewItem: ./app/components/NewItem.js
Listing 11.13. NewItem in the Application component: ./app/components/application.js
Listing 11.14. Enabling live reload: ./app/main.js
Listing 11.15. Setting up hot module reloading: ./app/main.js
Listing 11.16. Adding Babel support for hot module reloading: ./.compilerc
Listing 11.17. Using AppContainer to subscribe to updates: ./app/renderer.js
Listing 11.18. Using import() to asynchronously load dependencies: ./app/renderer.js
Listing 11.19. Using async/await to asynchronously load dependencies: ./app/renderer.js
Chapter 12. Persisting user data and using native Node.js modules
Listing 12.1. Adding a postinstall hook: /package.json
Listing 12.2. Setting up an SQLite database: ./app/database.js
Listing 12.3. Creating a table to store items: ./app/database.js
Listing 12.4. Passing the database into the application component: ./app/renderer.js
Listing 12.5. Fetching items from the database: ./app/components/Application.js
Listing 12.6. Implementing the ability to add items to the database: ./app/components/Application.js
Listing 12.7. Letting the database handle incrementing the ID: ./app/components/NewItem.js
Listing 12.8. Marking items as packed: ./app/components/Application.js
Listing 12.9. Marking all items as packed: ./app/components/Application.js
Listing 12.10. Deleting items: ./app/components/Application.js
Listing 12.11. Passing in delete methods: ./app/components/Application.js
Listing 12.12. The Items component: ./app/components/Items.js
Listing 12.13. The Item component: ./app/component/Item.js
Listing 12.14. Storing the database in the appropriate location: ./app/database.js
Listing 12.15. Setting up a store in IndexedDB: ./app/database.js
Listing 12.16. Getting all of the items from IndexedDB: ./app/database.js
Listing 12.17. Adding an item to IndexedDB: ./app/database.js
Listing 12.18. Updating an item in IndexedDB: ./app/database.js
Listing 12.19. Marking all items as packed: ./app/database.js
Listing 12.20. Removing an item from IndexedDB: ./app/database.js
Listing 12.21. Deleting all unpacked items from IndexedDB: ./app/database.js
Listing 12.22. Updating the Application component to use IndexedDB: ./app/components/Application.js
Chapter 13. Testing applications with Spectron
Listing 13.1. Setting up Mocha as a test script: ./package.json
Listing 13.2. Writing up Spectron with the test runner: ./test/spec.js
Listing 13.3. Writing a test to count the number of windows: ./test/spec.js
Listing 13.4. Writing a test to verify the window title: ./test/spec.js
Listing 13.5. Testing that the developer tools are not open: ./test/spec.js
Listing 13.6. Testing the content of the Copy from Clipboard button: ./test/spec.js
Listing 13.7. Testing the initial state of the UI: ./test/spec.js
Listing 13.8. Testing a click interaction: ./test/spec.js
Listing 13.9. Moving the cursor in a test: ./test/spec.js
Listing 13.10. Accessing Electron APIs in a test: ./test/spec.js
Listing 13.11. Testing that the application writes to the clipboard: ./test/spec.js
Chapter 14. Building applications for deployment
Listing 14.1. Adding a build script: ./package.json
Listing 14.2. Customizing the applications name and version: ./package.json
Listing 14.3. Building the application with a custom icon: ./package.json
Listing 14.4. Building for multiple platforms: ./package.json
Listing 14.5. Building for multiple platforms with asar: ./package.json
Listing 14.6. Using Yarn as your package manager: ./package.json
Chapter 15. Releasing and updating applications
Listing 15.1. Creating a file to configure and start up the Crash Reporter: ./app/crash-reporter.js
Listing 15.2. Starting the crash reporter in the main process: ./app/main.js
Listing 15.3. Starting the crash reporter in the renderer process: ./app/renderer.js
Listing 15.4. Creating a simple crash reporting server
Listing 15.5. An example of the JSON metadata from a crash report
Listing 15.6. Updating the crash reporter to report uncaught exceptions: ./app/crash-reporter.js
Listing 15.7. Setting up a server route to receive reports of uncaught exceptions
Listing 15.8. Updated Mac packaging script: ./package.json
Listing 15.9. Windows installer configuration: ./scripts/windows.js
Listing 15.10. Setting up Squirrel events in the main process: ./app/main.js
Listing 15.11. electron-squirrel-startup
Listing 15.12. Implementing Electron’s autoUpdater: ./app/auto-updater.js
Chapter 16. Distributing your application through the Mac App Store
Listing 16.1. Setting up the application: ./scripts/mas/info.plist
Listing 16.2. Setting parent permissions: ./scripts/mas/parent.plist
Listing 16.3. Extending permissions: ./scripts/mas/child.plist
Listing 16.4. The build script
Listing 16.5. Adding applications to particular categories: ./scripts/info.plist
Listing 16.6. Setting Fire Sale to be available to open Markdown files: /script/info.plist
Appendix Appendix. Code samples from Fire Sale and Clipmaster 9000
Listing 1. Fire Sale’s main process: ./app/main.js
Listing 2. Fire Sale’s renderer process: ./app/renderer.js
Listing 3. Fire Sale’s application menu: ./app/application-menu.js
Listing 4. Fire Sale’s renderer process: ./app/renderer.js
Listing 5. Fire Sale’s renderer process: ./app/renderer.js
Listing 6. Fire Sale’s application menu: ./app/application-menu.js
Listing 7. Fire Sale’s main process: ./app/main.js
Listing 8. Clipmaster 9000’s main process: ./app/main.js
Listing 9. Clipmaster 9000’s renderer process: ./app/renderer.js