Tutorial

Intro to Electron.js - Part 1: Setup

Published on August 24, 2019
    Default avatar

    By Joshua Hall

    Intro to Electron.js - Part 1: Setup

    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.

    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.

    Prerequisites

    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.

    Installation

    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
    

    File Structure

    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
    

    Setup

    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.

    package.json
    {
      "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.

    index.html
    <!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.

    MenuBar.js
    const menuBar = [];
    
    module.exports = menuBar;
    

    Window

    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().

    app.js
    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);
    });
    

    Conclusion

    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.

    Learn more about us


    About the authors
    Default avatar
    Joshua Hall

    author

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    Leave a comment
    

    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!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more
    DigitalOcean Cloud Control Panel