Hey there busy developers! Are you looking for a quick and easy way to get started with Electron and React/TypeScript? Look no further! In this article, we'll walk you through the process of creating a boilerplate for a desktop app using these technologies.

Now, I know what you're thinking: "But I've never worked with Electron before and I don't have time to read the documentation!" Don't worry, that's exactly who this tutorial is for. We'll keep things as simple and streamlined as possible, so you can get your app up and running in no time.

Now, I should note that this isn't the only way to set up an Electron app. But it's definitely one of the fastest, and it's perfect for those who are short on time and just want to get things up and running quickly.

So, let's get started!

Before we dive in, it's important to understand the basic structure of an Electron app. Essentially, it's a single web application that is embedded in a Chromium/Electron/Node.js frame. To help illustrate this, take a look at the image below, which shows the build process of an Electron app:

Let's start by creating a basic react app using create-react-app with the command

npx create-react-app ./ --template typescript

This will create an empty react app in the current directory.

Now let's install electron with the command

npm install electron

and then create a directory called electron with the following files:

  • index.ts
  • preload.ts
  • tsconfig.json
  1. index.ts

The index.ts file is the entry point for Electron. It contains all the necessary instructions to start a basic Electron browser window and load the index.html file from the build folder. This file, in turn, loads all the bundles created by the build script of React-scripts. The content of the index.ts file includes inline comments that provide explanations for each step of the process.

Here is the code:

import { app, BrowserWindow } from 'electron';
import * as path from 'path';

let mainWindow: Electron.BrowserWindow | null;

function createWindow() {
  // Create the browser window.electron
  mainWindow = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });

  // and load the index.html of the app.
  mainWindow.loadFile(path.join(__dirname, 'index.html'));

  // Open the DevTools.
  // mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
  mainWindow.maximize();
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
  createWindow();
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On OS X it"s common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});

2. preload.ts

You can use preload.ts which will be loaded before other scripts run on the main page. This script will always have access to both electron APIs and node APIs(and also the browser APIs) no matter whether node integration is turned on or off.

Since the app that we are building is pretty basic, it will not have much content.

// All of nodeJS APIs are available in the preload process
// it has the same sanbox as chrome extension
window.addEventListener('DOMContentLoaded', () => {});

export {};

3. tsconfig.json

If you've worked with TypeScript before, you're probably familiar with the tsconfig.json file. For those who may not be familiar, tsconfig.json is a configuration file that allows you to specify the root-level files and compiler options needed to compile a TypeScript project. The presence of this file in a directory indicates that the directory is the root of a TypeScript project. You can find more information about tsconfig.json and its various properties in the TypeScript documentation.

here

In our case, the content should look like the following:

{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "sourceMap": true,
    "outDir": "../build",
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    }
  },
  "include": [
    "**/*"
  ]
}

Now the last thing that we have to do is configure the scripts in package.json  exactly as the image at the beginning of this post describes it.

   {
      "scripts": {
         "build:web": "PUBLIC_URL=./ react-scripts build",
         "build:desktop": "tsc -p electron/tsconfig.json",
         "start:desktop": "npm run build:web && npm run build:desktop && electron ./build/index.js",
     }
   }

Now that we have everything set up, we can run the command npm run start:desktop and see that app is built in an electron frame.

And that's it, you have created a desktop app with Electron & React/Typescript.

Bonus

  1. Creating executables for all platforms (Windows, Linux, macOS) with electron-builder

There are multiple packages to use to create executables for an electron app. There are lots of tutorials online on how to use them but I found electron-builder quite easy to set up and to understand.

Let's start by adding the configurations in the package.json file. It's a build property added to the root of the JSON file.  

  "build": {
    "extraMetadata": {
      "homepage": "./",
      "main": "build/index.js"
    },
    "productName": "my-app-name",
    "appId": "my-app-id-or-version",
    "files": [
      "build/**/*",
      "node_modules/**/*"
    ],
    "mac": {
      "category": "public.app-category.productivity",
      "target": [
        "dmg",
        "zip"
      ],
      "icon": "src/Assets/img/unix.icns"
    },
    "linux": {
      "maintainer": "john@doe.com",
      "target": [
        "tar.gz",
        "deb"
      ],
      "icon": "src/Assets/img/unix.icns"
    },
    "win": {
      "target": [
        "zip",
        "dir"
      ],
      "icon": "src/Assets/img/windows.ico"
    }
  }

Now, let's add scripts to trigger the creation of the files for all operating systems

    "prebuild:package": "npm run build:web && npm run build:desktop",
    "build:package:windows": "npm run prebuild:package && electron-builder --win",
    "build:package:linux": "npm run prebuild:package && electron-builder --linux",
    "build:package:mac": "npm run prebuild:package && electron-builder --mac",
    "build:package:all": "npm run prebuild:package && electron-builder --win --linux --mac"
 

And there you have it. I think the names of the scripts speak for themselves. No further explanation is needed.

2. Automatic updates of the electron app in production

Automatic updates of the electron app in production can also be achieved in many ways but the most popular one is doing it via an "update server". I think that one is subject to a whole new blog post that I will publish in the future if I have time.

References:

  1. https://dev.to/achuthhadnoor/getting-started-with-electron-typescript-react-and-webpack-3ik4
  2. https://awsm.page/electron/how-to-use-preload-script-in-electron/
  3. https://www.electronjs.org/docs/latest/tutorial/updates