You might have come across the main process and renderer process in Electron. This is a simple explanation of them.
Main process
The main process takes care of starting and running your app. In the electron tutorial app you can see this line in package.json:
This is the primary entry point to an electron app. And this is running in the main process. All the files you require from this file will be running in the main process as well.
If we would call process.type and log it with console.log() the word “browser” would turn up in the terminal running the app.
console log in main process
Renderer process
The renderer process takes care of showing your app in the Chromium browser. When the app is ready to show the electron tutorial app runs this command in main.js:
The javascript files you include from index.html or any other html-document is running in the renderer process. If we would run the same console.log() call as above, the word “renderer” would show up. But this time in the developer tools of chromium:
console log in renderer process
Documentation
So what API calls can we do from the different processes? The official documents are kind to us and list them under Main Process and Renderer process. But there are also api-calls that work in both processes.
Communicating between the processes
The api allows us to communicate between the processes. You can do that with remote which provides a simple way to do inter-process communication between renderer and the main process.
IPCRenderer and IPCMain
The api also allows us to use ipcRenderer and ipcMain to help us send events between the different processes. We can then listen to these events and implement the functionality we need.
Let us add localization to the electron tutorial app. We will look at translating both in the main and renderer process.
I tried some of the already existing npm-packages that helps with translating your app. They were good but didn’t feel 100% right to me. Some of them used .po-files, some of them were too advanced. So I decided to write a simpler one on my own. This is just a matter of taste. If you find another way that suits you better you should do it like that instead.
The localization script will store translations in .js files with a json-structure. It will use english as a fallback language, and try to use the users language by default. If no translation is found the original phrase will be sent back to be used.
1.Adding the script
Create a new folder in the project called translations. Create a new .js file and copy the contents below and save the file as i18n.js (why i18n?)
In the i18n constructor the script first checks if a language file for the current users locale exists. If it does that file is loaded. If the file does not exist the script loads the fallback language in en.js.
the __ function takes a phrase as an argument and checks if that is translated in the loadedLanguage. If it’s not it returns the phrase sent to the function.
This line takes care of loading app from either the main(mainmenu.js) or renderer(from index.html) process.
2.Adding translation files
Since i am from Sweden I will locate the tutorial app into Swedish. So I will create en.js and sv.js in the translations folder. To know what you should name your file so that the i18n script will find it and load it you can add this to main.js which will log the locale to the terminal(just add .js to it):
This is how the structure in the translation files should look. This is what en.js will look like:
And this is what my sv.js looks like:
3.Translating the menu (Main process)
As you might have guessed when reading the translation they look like menu items. So let us translate the menu that was added in the last tutorial.
Open up mainmenu.js that is located in the menu folder and add this require statement to the top of the file:
Now all we need to do is call i18n.__() for every menu item. These are what the first three looks like, here is the fully translated menu file.
What you do is add the label: attribute to the menu item, which gets the translated value from i18n__().
4.Translating navigation menu in index.js (Renderer process)
Create a new file in assets/js/ called translations.js. In this one we’ll use jquery to set the translated strings to our html-markup.
Open index.html and add i18n int the list of scripts.
In translations.js it’s plain jquery to set the text of the elements that you wish to translate:
This is just two translations that are added. You can see the full file here.
The app now looks like this when running it on an os set to Swedish language:
electron tutorial app windows - translated to swedish
This tutorial shows you how to add an Electron menu to your app. It will also make standard keyboard shortcuts, like copy and paste, work on MacOS.
We’ve actually got our work pretty much done for us thanks to the Electron documentation giving us a good template to use. We just need to implement and do some changes to it (If you want to that is). As always this tutorial uses Electron tutorial app as a canvas so you can download and/or look at the code on github.
1.Adding the menu
Open up a new file and paste this menu definition to it (this is the code from the documentation, with minor adjustments):
Save this in a new folder called menu, and why not name the file mainmenu.js
If you take a look at the two last lines in mainmenu.js you see two calls, one to buildFromTemplate(), which basically takes the array defined above, and creates a menu from it. Then we pass the menu to setApplicationMenu()
2. Showing the menu in the app
Now open up main.js and add require(‘./menu/mainmenu’) after creating the window. In the Electron tutorial app it is added to line 45, right before closing the createWindow function. We add it there because the call to setApplicationMenu needs to been done after the ready event is fired. Which it has in createWindow.
If you start the app now, you can see that you have a different menu already.
3. Menu items
Let us look at what the mainmenu.js contains. It’s an array that defines MenuItems.
Label
Labels are what the menu item will say when it is displayed. It is required to set when you are defining a menu item that does not use Role(which we will look at soon). You can use this when localizing your menu items.
Submenu
A submenu is what you think it is. It is an array containing menuitems for a submenu.
Role
Electron provides us with roles that are predefined for Platform specific menu items such as undo, redo and those standard functions. The existing roles are:
undo
redo
cut
copy
paste
pasteandmatchstyle
selectall
delete
minimize - Minimize current window
close - Close current window
quit - Quit the application
togglefullscreen - Toggle full screen mode on the current window
resetzoom - Reset the focused page’s zoom level to the original size
zoomin - Zoom in the focused page by 10%
zoomout - Zoom out the focused page by 10%
On macOS role can also have following additional values:
about - Map to the orderFrontStandardAboutPanel action
hide - Map to the hide action
hideothers - Map to the hideOtherApplications action
unhide - Map to the unhideAllApplications action
startspeaking - Map to the startSpeaking action
stopspeaking - Map to the stopSpeaking action
front - Map to the arrangeInFront action
zoom - Map to the performZoom action
window - The submenu is a “Window” menu
help - The submenu is a “Help” menu
services - The submenu is a “Services” menu
When specifying role on macOS, label and accelerator are the only options that will affect the MenuItem. All other options will be ignored.
Accelerator
If you scroll down a bit in mainmenu.js to line 43 you can see something called accelerator. With the accelerator you can add keyboard shortcuts to your menu item. Built in accelerators are:
Command (or Cmd for short)
Control (or Ctrl for short)
CommandOrControl (or CmdOrCtrl for short)
Alt
Option
AltGr
Shift
Super
One interesting accelerator to look at is the CommandOrControl. It uses the command button on macs, but on windows it maps to control instead since Windows doesn’t use the command button.
click
When a menuItem is clicked you can define what code will be executed by defining a click event.
Type
You can se a type to a menuitem, a type can for example be a separator. If you look at line 56 in mainmenu.js you can see it being used. But there are more types defined:
type String - Can be normal, separator, submenu, checkbox or radio.
In this electron packager tutorial we will look at how to create MacOS, Windows and Linux executables with an app icon. This is also a continuation of the Electron app icon post, so start there if you haven’t read it (It’s short, i promise).
In this tutorial I package the application on Windows, macOS and Ubuntu Linux. There are some information about building Windows apps from non-Windows platforms in the Electron packager readme.
1. Install Electron packager
Electron packager is created by electron-userland and this is what they say about it:
"Electron Packager is a command line tool and Node.js library that bundles Electron-based application source code with a renamed Electron executable and supporting files into folders ready for distribution."
So lets go ahead and install it. Run these commands in the terminal in the app folder:
2. Setting productname and electron version
Electron packager looks for a product name in package.json, so lets go ahead and add one. We also need to add what version of electron to package the app with.
Lets begin with the electron version. We’ll add that from the terminal with this command:
Now when that is done open up package.json and add a productname:
3. Building MacOS, Windows and Linux package from the terminal
To get to know what all these flags do, and what more flags exists you can read the electron-packager api.
MacOS
Now you can run this command from the terminal to build a package for mac:
Electron packager mac
Windows
And to build for Windows you can run this from the git bash:
Electron packager windows
Linux
Electron packager ubuntu linux
overwrite: replaces any existing output directory when packaging.
platform: The target platform to build for
arch: the architecture to build for
icon: sets the icon for the app
prune: runs npm prune –production before packaging the app. It removes unnecesary packages.
out: the name of the directory where the packages are created.
4. Shortcuts
To make it easier to create new builds we can create scripts in package.json so that we don’t have to remember all these settings. Add the scripts below, making your package.json look like this:
It’s time to add Electron app icons to the Electron tutorial app. For this we need a png-icon, a .icns for macs and a .ico for windows. For Linux we only need the pngs.
This code is added to the Electron tutorial app on github. Have a look at that repository if you would like to see all the source code.
The icons need to be set when creating a new BrowserWindow. But they need also be set when packaging the app. So by setting it in the code won’t make any difference when debugging your app with electron . That’s why we’ll first take a look at the code. Then we’ll take a look at packaging our app with electron-packager. But don’t worry, it’s an easy task.
1. Creating our icns and ico-files
First we need an icon that is 1024x1024 pixels large and saved in PNG. I’ve got one looking like this:
Electron tutorial app icon
Now go to ICONVERT ICONS and upload the PNG and the service will take care of creating the other icon-formats.
2. Folder structure
Now create a folder structure that looks like this:
electron icon folder structure
Create a folder called icons in the assets folder. And in that folder create one folder called mac, one called png and one called win. Put the .icns-file into the mac folder, the pngs in the png folder and the .ico file in the win folder.
3. Updating main.js with path to icon
Open main.js and add icon: path.join(__dirname, 'assets/icons/png/64x64.png') when instantiating the BrowserWindow. But also var path = require(‘path’) at the top of the main.js.
At this point you can see the icon when running the app in Ubuntu. (Read how to get going with electron in ubuntu).
Electron icon ubuntu
The next step is to create an executable for MacOS and Windows with the icon we need to package the app. This next step is covered in Electron packager tutorial.