DEV Community

Mitch Pierias
Mitch Pierias

Posted on

The Dream Team — React with Electron

So you ‘re either a React developer dabbling into the world of electron, or your looking to extend the abilities of Electron. Either way, you’ve ended up here because you’ve asked yourself the same question that took me down the rabbit hole, “How can I use React inside Electron?”.

I’m not going to be making anything spectacular in this example. To be honest, I had trouble compiling my own Electron project with React, so I simplified everything down to this boilerplate template. In this example, we’re simply going to make React compile our basic project, then build our application distributions using Electron. The complete code for this example can be found here on GitHub.

Creating the Project

Before we can start building our electron application we first need to install a few dependencies and define our project structure. Firstly, create a new directory for your project and navigate inside, then run npm init and fill out the prompts to create your project boilerplate.

mkdir reactron && cd reactron
npm init

Now we’re ready to start installing our dependencies like React and React DOM! We’re also installing path as a production dependency cause we will be using it in with Electron later.

npm install --save react react-dom path

I’m not going to go over the React code, that could take a very long time depending on how far we choose to go. So I’m going to assume you know the basics. If not, you can just copy the files in the ./src directory from the GitHub repo and follow one of these tutorials if you’d like to learn more.

Webpack Setup

Now we need to compile our React project down into a single bundle, for this we will use Webpack.

npm install --save-dev webpack webpack-cli

We’re also going to need webpack loaders like babel, style loaders and html compilers, let’s install those and delve a little deeper into what they do.

npm install --save-dev babel-core@6 babel-loader@7 babel-preset-env@1 babel-preset-react@6

Babel is the loader responsible for parsing all our fancy new-age Javascript into the currently supported specification ES5.

  • babel-core: Transforms your ES6 code into ES5.
  • babel-loader: Webpack helper plugin to parse ES6 dependencies into ES5.
  • babel-preset-env: Determines which transformations/plugins to use and polyfills.
  • babel-preset-react: Presets for all React plugins.
npm install --save-dev css-loader style-loader html-webpack-plugin
  • style-loader: Compiles the referenced css files in our React components and injects them into the build file.
  • css-loader: Is the parser to help Webpack interpret and transform our CSS.
  • html-webpack-plugin: Outputs a compiled html file with resources adn tags linked.

There’s going to be allot of dependencies building up now… don’t worry, it’s just because of Webpacks extensability. Let’s define our project structure and start coding our resources, your project should resemble something like the following;

Reactron
|- assets
  ...react-assets...
|- build
  |- bundle.js
  |- index.html
|- dist
  ...electron-build-files...
|- node_modules
  ...installed-modules...
|- src
  |- index.js
  |- index.html
  |- index.css
|- package.json
|- main.js
|- webpack.config.js

Configuring Webpack

Now we’re ready to start configuring Webpack to bundle our React project and resources into our ./build directory for Electron. To start, open webpack.config.js and import the webpack, path and html-webpack-plugin modules.

const webpack = require('webpack');
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");

HTML-Webpack-Plugin

The html-webpack-plugin will take care of compiling our entry index.html file after webpack has done it's magic.

const htmlPlugin = new HtmlWebPackPlugin({
 title: "Reactron",
 template: "./src/index.html",
 filename: "./index.html"
});

Then we will configure our html-webpack-plugin. This will handle injecting resources and data into our ./src/index.html template through the Webpack build process, outputting the compiled result along with the bundled Javascript into the output directory.

The Webpack Build Pipeline

Now we are finally ready to configure our Webpack build pipline. Below everything we just wrote, define the following;

module.exports = {
 entry: './src/index.js',
 target: 'electron-renderer',
 output: {
  path: path.resolve(__dirname, 'build'),
  publicPath: './',
  filename: 'bundle.js'
 },
 module: {
  rules: [
   {
    test: /\.js$/,
    exclude: [
     /node_modules/,
     /.json?/
    ],
    use: {
     loader: 'babel-loader',
     query: {
      presets: ["env","react"]
     }
    }
   }, {
    test: /\.(s*)css$/,
    use: ['style-loader','css-loader']
   }
  ]
 },
 plugins:[
  htmlPlugin
 ],
 resolve: {
  extensions: ['.js','.jsx']
 }
}

I don’t want too delve deep into Webpack, but you can read the the official documentation and examples here if you’d like to explore it further. This code snippet is essentially telling Webpack where our entry file is, where we want to output, and using what modules and plugins.

Electron

We’ve now build our Electron renderer with React, bundled with Webpack, and now we’re ready to begin coding our Electron application to serve it all.

npm install --save-dev electron

Coding our Electron Application

Let’s open the ./main.js file and copy in the following;

const { app, BrowserWindow } = require('electron');
const path = require('path');

let mainWindow = null;

function createWindow() {

 mainWindow = new BrowserWindow({
  width:600,
  height:400
 });

 mainWindow.loadFile(path.resolve(__dirname,'build/index.html'));

 mainWindow.on('closed', () => {
  if (process.platform !== 'darwin') app.quit();
 });
}

app.on('ready', createWindow);

This is the absolute minimum code to start an Electron application. We’re importing our modules path and the app and BrowserWindow components from electron, then defining an empty mainWindow reference and createWindow() function before attaching it to the app.on(‘ready’) event. Our createWindow function is initializing a new BrowserWindow, loading the ./build/index.html file we compiled with Webpack earlier, and handling the mainWindow.on(‘closed’) event.
Running the App

And that’s it! We can execute npm webpack --mode production to compile and then npm electron . to start our Electron application. Let’s complete our project by compiling everything into a distribution with electron-builder.

Electron Builder

npm install --save-dev electron-builder

The Build Property

The majority of our electron-builder configuration happens inside the build property within our package.json.

"build": {
  "productName":"Reactron",
  "appId":"com.reactron.app",
  "directories": {
    "buildResources":"build",
    "output":"dist"
  }
  ...
}

We’re defining our productName which is self explanatory and the appId which is typically a unique identifier like a URL on the web. The important property is the directories, here you’ll specify the buildResources where Electron will find your bundled Webpack output, and the output setting which defines the directory to output the build.

"directories": {
  ...
},
"files": [
  "**/*",
  "build/**/*",
  "node_modules/**/*"
]

Now we specify the files to scan and package into our application bundle and we’re ready to run!

node electron-builder

Top comments (0)