Soooo… yeah, I’ve been going on a Node / JavaScript binge for the past month or so. There’s so much cool stuff you can do. Last time I wrote a blog post about cross platform command line apps and those are cool, this time I started playing around with a cross platform GUI application. There are a couple of competing technologies in the Node ecosystem if you want to build such a thing, they’re basically doing the same thing. NW.js is an Intel thing and Electron is a Microsoft thing. Electron is more popular supposedly so… I decided to go with that.
This is probably gonna be a 3 part series of blog posts just ‘cos it got so ridiculously long. Apologies for that 🙂
Electron
The idea behind Electron is simple. Node is already just basically the Javascript engine stripped out of the Chromium browser, plus a few libraries. Electron is just… adding some of the browser functionality back so that you can display a front end. ivermectin vs imidacloprid Bang in a few libraries to do common OS type things like display file open dialogs and Bob is well on his way to being your uncle. The reason this is cool is that you now get to build your front end with HTML. Good Lord! We can code like it’s 1999 . <br>
Forsooth!
Hello World
So… ja.. the actual point of this blog post. OK let’s go from the top. Electron apps are Node apps, so you can start with a good old
npm init && git init && npm install --save-dev electron
That gives you a package.json
and installs electron as a dev dependency.
There’s a decent Hello World tutorial over at the Electron website so… ya know, head over there for more in-depth details, and I’ll just point out the stuff that I found interesting.
Baby Steps
We’re gonna add an index.html
to be displayed when the user opens the app:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
And in main.js
we’re gonna load that page.
const { app, BrowserWindow } = require("electron");
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
});
win.loadFile("index.html");
};
app.whenReady().then(() => {
createWindow();
});
If you run that you’ll see the index.html
page displayed. To run it you’ll need to add a line like so: "dev": "electron ."
to the scripts
part of your package.json
, and then npm run dev
.
Adding CSS
OK so the page is very boring at present and what better way to unborify it than to add style? I just went and grabbed W3.CSS from here. But you can in principle use any CSS. treating goat lice with ivermectin
You add that to your page like normal in the <head>
portion of index.html
:
<link rel="stylesheet" href="w3.css" />
And let’s add some styling information in the body:
<div class="w3-panel w3-teal">
<h1>Hello World!</h1>
</div>
Much better 🙂 If you run that you will now see a nice styled banner displayed.
Customizing the menu
If you run the app as it is at present you’ll see you get the default Electron menu displayed, that’s a pain. We want to be able to add our own menu options to the app. This is all detailed in the Electron docs, by the way, just… not in one place. Let’s modify main.js
. First we need a function to create the menu:
const { Menu } = require("electron");
const createMenu = () => {
const isMac = process.platform === "darwin";
const template = [
{
label: "&File",
submenu: [
isMac ? { role: "close" } : { role: "quit" },
],
}
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
Note the isMac
thing up above. Of course Apple have to be different ‘cos Steve Freaking Jobs is a freaking genius or something. Apparently default behaviour for Apple programs is not to quit the application when the user tells them to… ya know… quit the application… but to just close all windows. Anyway this necessitates a few more modifications to main.js
to make everything work:
app.whenReady().then(() => {
createMenu();
createWindow();
app.on("activate", function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});
Electron’s process model
You can find further details here but the essential thing to understand is that the Main process is the only process that’s allowed to communicate with the operating system in an Electron app, each Main process spawns multiple Renderer processes which are the things that actually get displayed as BrowserWindow
s.
Renderer processes do not have access to Node functionality, that’s all handled in the Main process. So when your user e.g. clicks a button in your app and you want to do operating system type things in response you have to communicate with the Main process via Interprocess Communication (IPC). Electron provides a few different ways to do this, we’ll explore it in a bit more detail later.
Adding functionality
So right at the moment all we have is an app that can display a webpage, which ya know… I might as well just use an internet browser. To really explore the goodness that is Electron we wanna actually make it do something so… the thing I thought was, let’s make this thing into a text editor.
We’re gonna need to:
- Open and Save text files. This has to be done in the Main process.
- Display them for editing. This obviously has to be done in the Renderer process, which means we need our Main and Renderer processes to communicate.
OK so the design is gonna be like this:
- a textarea inside
index.html
to display text - File Open / Save / Save As functionality in our app menu
- use the electron
dialog
module to display Open and Save dialogs using the operating system native ones - use Node
fs
module to actually open and save text files - Use the electron
contextBridge
,ipcMain
andipcRenderer
modules to send and receive text between the Main and Renderer processes.
Continued in Part II
OK so we’re gonna leave it there for this blog post. If you want to go look at the final product which… I have to warn you is not anything really special… then the github link is here. Otherwise, I challenge you to do something fun with your own hello world Electron app involving opening and saving files, and displaying stuff on screen 🙂