For some time I have been intrigued by Electron. I got the basic idea that it is essentially a wrapper for a web application that can act as a cross-platform desktop application.
With that being said, I wanted to go on a journey to learn about building Electron Apps. During this journey, several things felt important for me to note. These were more specifically around the Electron processes and not so much the web technologies which may be used inside the Electron App.
In this post I make use of a lot of extracts from the official Electron Documentation.
The code snippets below is for reference only and would require additional resource to get running. I created an Electron Apps - Starting Point wiki which contains more detail on these code snippets and can be followed to create a starting point for developing an Electron application with Vue 3, Vite, and Tailwind as the base.
Writing the wiki also resulted in a project demonstrating the IPC patterns discussed later on in this post.
Every Electron app has a single main process, which serves several purposes:
- It acts as the application's entry point.
- It runs the Node.js environment, which provides access to Node.js built-ins and installed packages, as well as full operating system access.
- It creates and manages application windows with the
BrowserWindowmodule by loading a web page in a separate Renderer process.
The Renderer process spawns a
BrowserWindow which renders the web content; this includes all user interfaces and app functionality. The entry point for the Renderer process is an HTML file and should be written with the same tools, frameworks, and paradigms that would be used for a typical, or "modern-day", web application.
By default, a Renderer process does not have access to run Node.js built-ins or installed packages, nor does it have full operating system access, like the Main process does. If this access is enabled for the Renderer process, critical security issues are introduced.
As previously mentioned, the Renderer process, which is to say the user interfaces, does not interact with Node.js and Electron's native desktop functionality, these features are only accessible from the Main process.
A preload script contains code that executes in a Renderer process before its web content begins loading and is attached to the Main process in the
BrowserWindow constructor's webPreferences option.
The preload script runs within the renderer context, but is granted more privileges by having access to Node.js APIs through exposing arbitrary APIs in the global window that the web contents can then consume.
Simply put, the preload script shares a global Window interface with the Renderer process, but at the same time can access Node.js APIs in the Main process which provides context isolation.
Context Isolation is implemented through the use of a
contextBridge module which exposes inter-process communication (IPC) to securely isolate privileged APIs from the rendered process loaded by the
webContents in the Main Process.
Inter-process communication (IPC) is used to perform many common tasks such as calling a native API from the UI or triggering changes in the web contents from native menus.
This communication occurs by passing messages through developer defined "channels" with the
This starting point application demonstrates the three different IPC patterns. Each of these patterns are implemented as Vue components.
In this pattern, the preload script exposes an
ipcRenderer.send API through a function call to the renderer, which sends a message that is then received by the
ipcMain.on API in the Main process.
Takes a form input or something similar in a method running in the renderer process and updates the window title in the main process.
contextBridge exposes the following API for the renderer to send on the
The Main process will call the
setTitle function when an event is received on the
Similar to the Renderer to Main (one-way) pattern, this pattern will wait for a result from the Main process by using an
ipcRenderer.invoke API, paired with
ping button in the renderer process, when clicked, will fire off an event which will receive a
pong from the main process.
contextBridge exposes the following API for the renderer to invoke the
The Main process will call the
pong function by handling the
The Main process can send a message to the Renderer process via its
WebContents instance. This
WebContents instance contains a
WebContents.send() method that can be used to send an event on a defined channel using the
ipcRenderer.on() API in the preload script.
Open a file explorer dialog using the menu button to read the file's name and send it to the Renderer process to be displayed.
Optional: The renderer will respond back using a callback function.
contextBridge exposes the following API for the renderer to wait on the
The Main process requires you to add application menu items with a click function call for the
selectFile function. This function sends the filename to the renderer on the
send-filename channel. The Main process will also wait for an event on the
file-displayed channel which the renderer will emit to using the callback.
If you enjoyed the post, please consider subscribing so that you can receive future content in your inbox :)
Psssst, worried about sharing your email address and would rather want to hide it? Consider using a service I created to help with that: mailphantom.io
Also, if you have any questions, comments, or suggestions please feel free to Contact Me.