Okay, let's make one thing clear !!! When I say busy developers I mean devs who have a lot in their hands, have never worked with Electron before, don't have time to go through the docs, and would like to have a basic Electron & React/Typescript up there real quick.

I wouldn't say - by all means - that this is the only way to set up an electron app. I just think it is one of the fastest ways to get it up pretty quickly.

So let's get started!!!

First things first, since it is obviously a single web application embedded in a Chromium/Electron/NodeJs frame.

Here is a breakdown image of the build process of the whole application:

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

This file is the entry point of electron it contains all the necessary instructions to start a very basic electron browser window, load the index.html file from the build folder which will load all the bundles created by the build script of react-scripts

The content has self-explanatory inline comments. Here it is:

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

Well, it's tsconfig.json  right ?!!! 😁. You should know about it if you have worked with typescript at least once.

If you don't know the use of it, here is what I found online that can help:

The tsconfig. json file allows you to specify the root level files and the compiler options that requires to compile a TypeScript project. The presence of this file in a directory specifies that the said directory is the TypeScript project root. ... JSON , it's various properties, and how to extend it.

Find more here

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 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 over an update server. I think that one is subject to a whole new blog post that you should look forward to.

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