Getting Started with Electron, Typescript, React and Webpack

Achuth Hadnoor

Achuth Hadnoor / April 23, 2021

5 min read

development
Achuth Hadnoor

If you are a web developer and you want to build a native app that solves a daily workflow problem or if you have a web app built completely and want to give users more of your app with native capabilities . Then there is an easy way to do that with electronJs.This tutorial will help you build a web application that works as a native app.

Let’s use a basic electron starter project and then enhance it to an enterprise ready application

Initialise and an empty electron project

We will first initialise an empty electron project that will look similar to an electron first app or electron quick starter repository

Electron has two processes one is main processelectron itself and other one is renderer process, where our web application runs.

Now let's install the dependencies

npm init -y
npm install --save-dev electron

Electron (main) entry point

// src/electron.js
const { app, BrowserWindow } = require('electron');function createWindow () {
  // Create the browser window.
  let win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  });  // and load the index.html of the app.
  win.loadFile('index.html');
}app.on('ready', createWindow);

Electron (render) entry point

<!-- // src/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <div id="app">
      <h1>Hello World!</h1>
    </div>
  </body>
</html>

We can run the app with npx electron src/electron.js. We’ll add this in our package.json as a script.

// package.json
"scripts": {
  "start": "electron src/electron.js"
}

Adding TypeScript

The boilerplate JavaScript is also valid TypeScript, so let’s rename src/electron.js to electron.ts. We just need to install the TypeScript compiler and configure it.

Install dependencies

npm install --save-dev typescript

TypeScript configuration

touch tsconfig.json

Update npm scripts

"scripts": {
  "build": "tsc src/electron.ts"
}

Adding Webpack

Next we’ll set up Webpack to optimize our application. Webpack configuration consists of an array of entry points. Webpack processes each entry point by passing the file (and its dependencies) through a loader. Loaders are selected via rules, often with a loader per file extension. Finally, Webpack dumps the output to a specified location.

We’ll create a single entry point for our electron main process, add a loader for all *.ts files to pass through the TypeScript compiler, and tell Webpack to dump the output alongside the source files.

Install dependencies

npm install --save-dev webpack webpack-cli ts-loader

Webpack configuration

// webpack.config.js
module.exports = [
  {
    mode: 'development',
    entry: './src/electron.ts',
    target: 'electron-main',
    module: {
      rules: [{
        test: /\.ts$/,
        include: /src/,
        use: [{ loader: 'ts-loader' }]
      }]
    },
    output: {
      path: __dirname + '/src',
      filename: 'electron.js'
    }
  }
];

Here’s a breakdown of each piece of the configuration:

  • mode: develop Development build (as opposed to production).
  • entry: './src/electron.ts Location of the entry point
  • target: 'electron-main' Specifies which environment to target; Webpack knows about the electron main process specifically.
  • test: /\.ts$/ Specifies that this rule should match all files that end with the .ts extension.
  • include: /src/ Specifies that all files within src should be considered for matching this rule.
  • use: [{ loader: 'ts-loader' }] Specifies which loader(s) to use when this rule matches.
  • path: __dirname + '/src' Directory where all output files will be placed.
  • filename: 'electron.js' Primary output bundle filename.

Update npm scripts

// package.json
"scripts": {
  "build": "webpack --config ./webpack.config.js",
  "start": "npm run build && electron ./src/electron.js"
}

Adding React

The React render process does not need to know it’s being used within an Electron context, so setting up React is similar to setting up a vanilla React project.

Install dependencies

npm install --save-dev react react-dom @types/react @types/react-dom

React entry point

// src/react.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';const Index = () => {
    return <div>Hello React!</div>;
};ReactDOM.render(<Index />, document.getElementById('app'));

TypeScript configuration

Our render entry point is .tsx and not .ts. The TypeScript compiler has built-in support for TSX (The TypeScript equivalent of JSX), but we need to tell TypeScript how to handle our TSX resources. Not surprisingly, we’re using the React TSX variety.

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "react"
  }
}

Next, we’ll create a new entry point in Webpack’s configuration. Webpack will process our entry point (and its dependencies) and load the result into our index.html via the html-webpack-plugin.

Install dependencies

npm install --save-dev html-webpack-plugin

Webpack configuration

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = [
  ...
  {
    mode: 'development',
    entry: './src/react.tsx',
    target: 'electron-renderer',
    devtool: 'source-map',
    module: { rules: [{
      test: /\.ts(x?)$/,
      include: /src/,
      use: [{ loader: 'ts-loader' }]
    }] },
    output: {
      path: __dirname + '/dist',
      filename: 'react.js'
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html'
      })
    ]
  }
];

This configuration is similar to that of our main process, but there are some new items:

  • target: 'electron-renderer' Specifies which environment to target; Webpack knows about the electron renderer process specifically.
  • plugins ... Specifies any plugins used during the build process. Plugins differ from loaders in that plugins operate at the bundle level and can more deeply integrate with the build process via hooks. Loaders operate at the file level. The HtmlWebpackPlugin will automagically add a reference to the output bundle in the specified template file.

Since the output path for our renderer files is no longer the src directory, we’ve instructed Webpack to put our resources in a new dist directory. Let’s do the same for the main process’ configuration.

// webpack.config.js
...
  output: {
    path: __dirname + '/dist',
    filename: 'electron.js'
  }

With our output files now inside the dist directory, we need to update our npm scripts to match.

"scripts": {
  ...
  "start": "npm run build && electron ./dist/electron.js"
}

Conclusion

Now we can see how Electron turns out to be suited for most of the web frameworks and Webpack is well suited for packaging multiple things at once.

Subscribe to my newsletter

In this weekly newsletter I'm going to share with you what's new and cool in the world of web development, with content for everyone, from beginners to pros. There's also an interview question of the week, where you can test your skills and I'll share the results the following week. I'll also send you jokes and stories. I won't spam though, I promise.follow me on Twitter.