Joshua Hall
In this article we’ll be learning how to develop our own native desktop applications using Electron.js. We’ll be making a basic todo list app to master the fundamentals behind creating menus, working with local data, and bundling our apps into something we can run on our local machine. If you ever wish to explore any of these options deeper, I would take a look at the official docs.
Only some Node.js basics are necessary, but since we’ll be using Nedb, which is built on MongoDB and Mongoose, being familiar with using a NoSQL database will be very helpful, which you can learn more about here.
We only need a few things to get things started.
electron
electromon
A version of nodemon for live reloading electron apps.nedb
A version of MongoDB and Mongoose that allows us to save data directly to our machine.electron-packager
A builder for our app so we can send and download it later.$ npm i electron electromon nedb electron-packager
All we really need to get started is a place to put our icons for our different operating systems, a HTML page with a client-side JavaScript file, and a file for our server. We’ll also break our Menu Bar into it’s own component since it can get a bit cumbersome.
* assets 📂
* icons 📂 // electron-packager needs a different logo format for every platform
* mac // mac and linux, since they take the same file type
* win
* src 📂
* MenuBar.js
* index.html
* script.js
* app.js
* package.json
For our project’s package.json file, the scripts object may seem complicated, but we’re just adding a start script and some build commands for when we’re ready to deploy to various platforms. In the build commands, make sure the --icon
path leads to the correct location and ProductName
equals the name of your app, we’ll worry about the icons later.
{
"dependencies": {
"electromon": "^1.0.10",
"electron": "^5.0.8",
"electron-packager": "^14.0.3",
"nedb": "^1.8.0"
},
"name": "electron-app",
"version": "1.0.0",
"main": "app.js",
"devDependencies": {},
"scripts": {
"start": "electromon .",
"package-mac": "electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/mac/icon.icns --prune=true --out=release-builds",
"package-win": "electron-packager . --overwrite --asar=true --platform=win32 --arch=ia32 --icon=assets/icons/win/icon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"Electron App\"",
"package-linux": "electron-packager . --overwrite --asar=true --platform=linux --arch=x64 --icon=assets/icons/mac/icon.icns --prune=true --out=release-builds"
},
"author": "",
"license": "ISC",
"description": ""
}
Let’s get our interface set up with just a basic HTML page. I will be using the Tailwind CSS framework to make it look a little nicer. All we really need is a form to enter our new items, and and empty ul
to append them onto later.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<title>Electron</title>
</head>
<body class="bg-gray-900 text-white flex flex-col items-center">
<form>
<input type="text" placeholder="New Item" class="bg-transparent rounded h-12 mt-4 pl-3">
<button type="submit" class="bg-blue-800 rounded h-12 w-16">Add</button>
</form>
<ul></ul>
<script src="./script.js"></script>
</body>
</html>
To avoid getting an error, we’re just going to set our menu bar to an empty array, and it’ll be passed to and rendered by app.js
. We’ll go into more detail on that later.
const menuBar = [];
module.exports = menuBar;
After requiring everything, we’re going to destructure all of the tools we need off of electron.
app
Controls the lifecycle of our app; whether it’s on, shutting off, reloading, etc.BrowserWindow
Establishes the window itself, it comes with a long list of options but all we really need is to tell it to use Node.js on our client side.Menu
Sets our menu bar from our template over in MenuBar.js
ipcMain
Controls event calls between the server and the client. It’s client-side counterpart, ipcRenderer
, sends our data to our server while ipcMain
will catch that before we can save the data to our machine.Since we are essentially just making a web page we can just pass our new window our page URL, which we can make a bit more palatable using url.format().
const electron = require('electron');
const url = require('url');
const path = require('path');
// Components
const menuBar = require('./src/components/MenuBar');
const { app, BrowserWindow, Menu, ipcMain } = electron;
let mainWindow;
app.on('ready', () => {
mainWindow = new BrowserWindow({
webPreferences: { nodeIntegration: true } // This will allow us to use node specific tools like require in our client side javascript.
});
mainWindow.loadURL(url.format({
// All this is doing is passing in to file://your_directory/src/index.html
pathname: path.join(__dirname, 'src/index.html'),
protocol: 'file:',
slashes: true
}));
// Shut down app when window closes
mainWindow.on('closed', () => app.quit());
const mainMenu = Menu.buildFromTemplate(menuBar);
Menu.setApplicationMenu(mainMenu);
});
Since this article started to get excessively long, I decided to break it into two parts to make it a bit more graspable. What we have so far makes a good boilerplate and In part 2 we’ll be going over the more interesting bits like communicating between the client and the server, managing our database, and bundling our app. You can find the repo for the completed example here.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!