Electron-builder ¶ A complete solution to package and build a ready for distribution Electron app for macOS, Windows and Linux with “auto update” support out of the box. Quickstart Electron is a framework that enables you to create desktop applications with JavaScript, HTML, and CSS. These applications can then be packaged to run directly on macOS, Windows, or Linux, or distributed via the Mac App Store or the Microsoft Store. The next time you issue a Ctrl+Shift+B command, you should get a nice build and have your application launched. Debugging Electron with VSCode VSCode takes the development experience one step further by allowing you to debug your code. Go to the debugger window and click on settings. The above command will launch the Docker container with your Electron App’s root folder mounted inside the /project/ virtual path. Once you get the docker’s container prompt – a Linux terminal by all means – type the following commands to get inside that folder, upgrade your Electron project’s Yarn packages, globally install the electron-builder package and, last but not least, build.
What is going on above?
- Line 1: First, you import the
app
andBrowserWindow
modules of theelectron
package to be able to manage your application's lifecycle events, as well as create and control browser windows. - Line 3: After that, you define a function that creates a new browser window with node integration enabled, loads
index.html
file into this window (line 12, we will discuss the file later) and opens Developer Tools (line 13). - Line 16: You create a new browser window by invoking the
createWindow
function once the Electron application is initialized. - Line 18: You add a new listener that tries to quit the application when it no longer has any open windows. This listener is a no-op on macOS due to the operating system's window management behavior.
- Line 24: You add a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
Have you ever wondered if you can build cross platform desktop apps with HTML, CSS and JavaScript?
It is possible with Electron.
This article is a step-by-step guide that will help you understand some core concepts of Electron.
By the end of this post, you’ll know the process of creating cross platform desktop apps with Electron, HTML and CSS.
Before we get started you can check out in advance the app we’re going to build in this tutorial.
Hear Me Type, as I named it, will have a simple but straightforward functionality: for every keyboard key pressed play a specific sound related to that key.
So if I press the “A” button, the app will play the sound of the letter A.
- Hear Me Type Tutorial app GitHub repository
- Hear Me Type GitHub repository (a more advanced version of the app. Recommended for more experienced Electron users)
The apps’ code will change once in a while as I’m adding new features and enhancements so be sure to check out the commits to see what’s new.
Without further ado, let’s find out more about Electron and create our first app!
What is Electron?
Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It uses Chromium and Node.js so you can build your app with HTML, CSS, and JavaScript similar to a web-based application.
Your newly created app will be compatible with Mac, Windows and Linux operating systems.
Other in-built features are:
- Automatic updates – enable apps to automatically update themselves
- Native menus and notifications – creates native application menus and context menus
- App crash reporting – you can submit crash reports to a remote server
- Debugging and profiling – it uses Chromium’s content module for finding performance bottlenecks and slow operations. You can also use your favorite Chrome Developer Tools within your app if you’d like
- Windows installer – you can create install packages. Fast and simple.
Getting Started
If you’re happy with what Electron offers, let’s dive deeper and create a simple Electron app.
Before we get our hands dirty, make sure you have the dependencies like Node.js installed (you can download it from here) and also a GitHub account where you can store your app and make changes to it.
Now that Node.js is installed and a GitHub account, open your Bash or Terminal and follow the instructions below to clone the Electron Quick Start Git repository to your computer. We’re gonna build our software upon this useful but minimal app:
# Clone the Quick Start repository
$ git clone https://github.com/electron/electron-quick-start
# Go into the repository
$ cd electron-quick-start
# Install the dependencies and run
$ npm install && npm star
t
When you have completed the steps above you should see that our app opens up in a window that looks like a browser’s window. And it is indeed a browser window!
The app’s window style changes depending on the Operating System’s default or customized window style. I chose to use the classic look of Windows. Groovy!
Like I was saying earlier, you can use Chrome’s Developer Tools inside your app. What you can do on your browser’s Developer Tools, can also be done inside the app. Outstanding!
Let’s have a look at the source code and the file structure of our app. Open up the project into your favorite text editor or IDE. I’m going to use Atom which is built on… you guessed it… Electron!
Folder and files structure of our newly created app.
We have a basic file structure:
electron-quick-start
- index.html
- main.js
- package.json
- render.js
The file structure is similar to the one we use when creating web pages.
We have:
index.html
which is simply an HTML5 web page and it serves one big purpose: our canvasmain.js
creates windows and handles system eventspackage.json
similar to Node.js’ modules, is the startup script of our app, which will run in the main process and it contains information about our apprender.js
is responsible for hosting the app’s render processes
You may have a few questions up until now, and one of them might be regarding the main process and render process thingies. What the heck are those little bastards and how can I get along with them?
Electron Build Mac
Glad you asked. Hang on to your hat ’cause this is probably new territory if you’re coming from browser JavaScript realm!
What is a process?
When you say process you think of an operating system level process which is in fact just an instance of a computer program that is being executed.
If I start my Electron app and check the Windows Task Manager/Activity Monitor for macOS, I can see how many processes are associated with my app.
Each of these processes run concurrently to each other but the memory and resources are isolated.
Let’s say I want to create a specific for loop
that increments something in one of my render processes.
The above incrementation is available only in the render process, it doesn’t affect the main process at all, thus the ‘This is a for loop’ message will appear only on the rendered module.
Main Process
The main process controls the life of the application. It has the full Node.js API built in and it is responsible for opening dialogs and other operating system interactions, creating render processes, and starting and quitting the app.
This process is commonly a file named main.js
, like in our case, but it can have whatever name you’d like.
You can also change the main process file by modifying it in package.json
file.
Just for testing purpose, change:
'main': 'main.js',
to
'main': 'mainTest.js',
See if your app still works.
Bear in mind that there can be only one main process.
Render Process
The render process is a browser window in your app. Unlike the main process, there can be multiple render processes and each is independent. Every render process is a separate process, meaning a crash in one won’t affect another. This is thanks to Chromium’s multi-process architecture.
These browser windows can also be hidden and of course, customized because they’re like typical HTML files, but in Electron we’ve also got the full Node.js API in here which means that we can open dialogs and other operating system interactions.
Think of it like this:
One question remains now. Can they both be linked somehow?
While these processes run concurrently and independently to each other, they still need to communicate somehow since they’re both responsible for different tasks.
For this there’s an interprocess communication system, or IPC. You can use IPC to pass messages between main and render processes.
This pretty much sums up the minimum knowledge about main process and render process you have to know before starting building an Electron application.
Now let’s get back to our code!
Make It Personal
Let’s give our app’s folder a proper name.
Change the folder name from electron-quick-start
to hear-me-type-tutorial
.
Reopen the folder with your favorite text editor or IDE and let’s further customize our app’s identity by opening up the package.json
file.
package.json
contains vital information about our app like its name, version, main file, author, license and so much more.
Let’s get a little bit of pride and put yourself as author of the app.
Find the 'author'
parameter and change it’s value to your name. It should look like this:
'author': 'Carol Pelu',
We also need to change the rest of the parameters. Modify the “name” and “description” for now. I find the following name and description appropriate for our app:
Awesome! Now our app has a new name and a short but straight to the point description.
Remember, you can always run npm start
in your bash to execute the app and see the changes you’ve made.
Let’s move forward and add the expected functionality of our app. We want to play a specific sound for every keyboard key that we press.
Oh, the Fun-ctionalitee!
What is an app without fun-ctionality? Nothing much…
Now we must take care of it and give our app the functionality it desires.
To make the app react to our input, we must first define an element to hook upon and then trigger the desired action.
In order to do that we will create an audio
element with specific id
s for the keyboard keys that we want. Then we will create a switch
statement to find out which keyboard key has been pressed, then play a specific sound of that key.
If this sound a little complex to you now, have no fear. I will guide you through every step.
Download this archive containing all the sound files we’ll be using. We’ll soon make use of them!
Open up the index.html
file and let’s create the <audio>
elements in order to embed the sound content in our app.
Inside the <body>
element, create a div
element with the “audio” class
tag.
Then inside the newly created div
element, create an <audio>
element with an id
of “A”, the source
tag of “sounds/A.mp3” and with a preload
attribute of “auto”.
We’ll use preload='auto'
to tell the app that it should load the entire audio file when the page loads. index.html
being the main file of the app, all of our sound files will be fully loaded when the app executes.
The code should look like this:
Now the <audio>
is pointing to an unknown source file. Let’s create a folder called sounds
and unzip all the sound files inside the folder.
Great! The only important thing that’s missing right now is the JavaScript code.
Create a new file called functions.js
and let’s require it within the index.html
file so that the JS code is ready for use when the app is running.
Electron Build Linux
Following the example of require(./renderer.js')
, right under it add this line of code:
require('./functions.js')
Your project should look like this:
Outstanding! Now that we have everything stitched up, it’s time for the moment of truth!
Open up the functions.js
file and add the following JavaScript code into the file. I’ll explain how it works in just a moment.
The code should look like this:
Open your bash in your project’s folder and type npm start
to run the app.
Tune up the volume of your speakers and press the A button on your keyboard.
#MindBlown
The JS code is pretty simple and straightforward.
We use the onkeydown
event on the document
object to find out which HTML element is being accessed within the document
object which is in fact our app’s main window.
Within the anonymous function we use a switch
statement whose purpose is to identify the Unicode value of the pressed keyboard key.
If the Unicode value of the pressed keyboard key is correct, the sound is played, otherwise throw a “not found” message into the console.
Whfiu! What a ride!
Maybe you’ve noticed that we have sound files to cover A-Z and 0-9 keys. Let’s use them too so they don’t feel the bitter taste of loneliness.
Head over to index.html
and create an <audio>
element for every key that we have a sound file for.
The code should look like this:
Yeah, of course you can copy-paste:
Awesome! Now let’s do the same thing for the JS code within functions.js
.
You can find the char codes (key codes) on this website.
But yeah, you can copy-paste this too:
Our app is now complete! Congrats!
The main functionality of the app is done, but there is still work to be done!
Polska ja! (Polish me!)
Even though the app is functional it still lacks some things here and there.
For example, within the index.html
file you can change the app’s title and the content that you want to be shown in the main window.
Moreover, the app has no design, no beautiful colors, no pictures with either cats or dogs.
Give freedom to your imagination and find out ways you can improve the app’s design!
The code isn’t perfect either. We have lots of identical code which can be optimized and improved in less lines of code and less painful for the eyes. Code duplication is bad practice!
Test It! Just Test It!
A good software must be thoroughly tested.
I’d suggest to begin with pressing every keyboard key to see what’s happening.
Best scenario is you will hear the audio for every keyboard key you have specified in the code, but who knows what will happen when you press multiple keys in a row as fast as you can or keys that are not even supposed to be pressed like the Home and NumLock buttons.
What happens when you minimize the app and try to press a key? Do you hear a sound? But what happens when you don’t have the app window selected and you press a keyboard key, do you still hear any sounds?
The answer is unfortunately a no.
This behavior is because of the architecture upon which Electron was built. It does allow you to get global keys, like you can do with the C# language, but you can’t register individual keystrokes. This is outside of the realm of normal use-cases for an electron application. I don’t know the real reason behind this caveat but I guess it has something to do with keyloggers and user’s privacy.
I want you to grab the code line by line and break it to see what is happening and what kind of errors is Electron throwing out. This exercise will help you become better at debugging. If you know the flaws of your app you then know how to fix them and make the app better.
In functions.js
file I have used a deprecated JavaScript event.
Once you find it I would like you to think about how you can replace this deprecated event without changing the functionality of the app.
Using deprecated code is bad practice and can lead to serious bugs you might not even know they exist. It’s recommended to read again the documentation of the language to see what has changed and stay up to date.
Conclusion
First of all I would like to thank and congratulate you for reaching this point!
You now have the knowledge to create a simple cross-platform Electron app.
If you want to dive deeper into Electron and see what I am working on make sure to check out Hear Me Type and my profile on GitHub.
Feel free to clone, fork, star and contribute to any of my public projects.
Last but not least, I’d suggest you to come back and read again this article from time to time as I will constantly update it according to what changes Electron will suffer over time.
Electron Build Windows
- 10 Rules of Studying Every Software Developer Should Follow - June 5, 2020
- How To Force Use Yarn Or NPM - May 21, 2020
- npm vs npx — What’s the Difference? - January 5, 2020