Getting Started with Electron, Typescript, React and Webpack
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 process, electron 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 pointtarget: '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 withinsrc
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. TheHtmlWebpackPlugin
will automagically add a reference to the output bundle in the specifiedtemplate
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.