Photo by Raphaël Biscaldi on Unsplash

If you’re new to Electron and prefer to use ReactJS, you might have stumbled upon this boilerplate on GitHub.

This boilerplate is great. However, it contains too much of the fancy stuff that I didn’t need. If you’re like me, I just want to drop my React project in Electron and see it work.

Here are the key points if you want to achieve that.


Combine Electron With Create React App or Not?

If you decide to combine Electron within CRA, your project would look like an ordinary React app, whereelectron-starter.js is the entry point for electron.

<span id="cdf5" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">├── Procfile
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── electron-starter.js
    ├── electron-wait-react.js
    ├── index.css
    ├── index.js
    └── logo.svg</span>
		

If this is what you’re looking for, here’s a thorough tutorial of how to do that: “Building an Electron application with create-react-app” by Christian Sepulveda.

But if you’re migrating a NodeJS app to Electron and you want to keep the back end (which is now the main process code) separated, you could try this structure.

<span id="6266" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">├── Procfile
├── app
│   ├── config
│   ├── events
│   ├── libs
│   ├── models
│   └── views
│       ├── js
│       │   └── preload.js
│       └── react
│           ├── README.md
│           ├── build
│           ├── package.json
│           ├── public
│           └── src
├── assets
│   └── icon.png
├── electron-wait-react.js
├── main.js
└── package.json</span>
		

In this case, main.js will be the entry point, and the build folder of Electron won’t conflict with CRA’s build folder.


Setup Dev and Prod Environment

Since you don’t want to restart your Electron app every time you make a change, you can specify that Electron use the URL of the React’s webpack-dev-server.

<span id="cea7" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">const { app, BrowserWindow } = require('electron');</span><span id="dcf9" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const path = require('path');</span><span id="975e" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const url = require('url');</span><span id="9b93" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">let mainWindow</span><span id="bb70" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">function createWindow () {</span><span id="94d7" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">// Create the browser window.</span><span id="3346" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">mainWindow = new BrowserWindow({</span><span id="33e4" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  width: 1024,</span><span id="c9f3" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  height: 728</span><span id="5e7d" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">});</span><span id="2092" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const startUrl = process.env.ELECTRON_START_URL || url.format({</span><span id="c02e" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">pathname: path.join(__dirname, 'app/views/react/build/index.html'),</span><span id="e78d" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">protocol: 'file:',</span><span id="d5d1" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">slashes: true</span><span id="9617" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">});</span><span id="b43d" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">mainWindow.loadURL(startUrl);</span>
		

If there’s an ELECTRON_START_URL as an environment variable, it will use that URL instead of the built version of React.

Thanks to Christian’s tutorial mentioned above, you can also use Foreman to manage and to log both Electron and React.

That’s where the Procfile comes in handy. In your Procfile, add the npm script that runs the React app and Electron app:

<span id="fc58" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">react: npm run react-start
electron: npm run electron-start</span>
		

And most of the magic happens in package.json.

<span id="29bf" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">{</span><span id="0433" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"main": "main.js",</span><span id="2408" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"scripts": {</span><span id="4507" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"start": "nf start -p 3000",</span><span id="da76" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"electron-start": "node electron-wait-react",</span><span id="9d12" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"react-start": "cd ./app/views/react && react-scripts start"</span><span id="72bc" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">},</span><span id="b7ff" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"devDependencies": {</span><span id="c90a" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"electron": "^6.0.9",</span><span id="3af2" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"electron-builder": "^21.2.0",</span><span id="8db9" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"foreman": "^3.0.1"</span><span id="1122" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">},</span><span id="1353" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"directories": {</span><span id="9b2e" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"buildResources": "assets",</span><span id="bf3f" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">"output": "release"</span><span id="142b" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">}</span><span id="22f8" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">}</span>
		

When you run npm start , it executes both of the commands in Procfile at port 3000.

And you might wonder, what does electron-wait-react.js do?

Similar to Christian’s version, I made a small adjustment to log messages from the Electron app.

It waits for React’s webpack-dev-server to start before launching the Electron app.

<span id="892a" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">const net = require('net');</span><span id="7aa9" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const port = process.env.PORT ? (process.env.PORT - 100) : 3000;</span><span id="4e10" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">process.env.ELECTRON_START_URL = `http://localhost:${port}`;</span><span id="4fde" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const client = new net.Socket();</span><span id="9eb9" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">let startedElectron = false;</span><span id="7f13" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">const tryConnection = () => client.connect({port: port}, () => {</span><span id="ac56" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> client.end();</span><span id="225e" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> if(!startedElectron) {</span><span id="5992" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  console.log('starting electron');</span><span id="fce1" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  startedElectron = true;</span><span id="c914" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> const { spawn } = require('child_process');</span><span id="8b99" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> const ls = spawn('npm run electron', [], { shell: true });</span><span id="9b3e" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> ls.stdout.on('data', (data) => {</span><span id="0bac" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  console.log(`${data}`);</span><span id="b0b5" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> });</span><span id="3df3" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> ls.stderr.on('data', (data) => {</span><span id="7772" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  console.error(`err: ${data}`);
 });</span><span id="c9be" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> ls.on('close', (code) => {</span><span id="5467" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  console.log(`child process exited with code ${code}`);</span><span id="08ad" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> });</span><span id="7865" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">}});</span><span id="7d51" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">tryConnection();</span><span id="1d18" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">client.on('error', (error) => {</span><span id="25b3" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;"> setTimeout(tryConnection, 1000);</span><span id="3c11" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">});</span>
		

Set Home Page in React package.json

If you build the app and you see a blank page, that’s because React cannot find its js and CSS files. In your package.json of React app, be sure to add:

<span id="3898" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">"homepage": "./"</span>
		

Use nodeIntegration

Finally, you have React running in Electron, but what if you want to use Electron modules inside of React?

Upon window creation, you can add in nodeIntegration in webPreferences.

<span id="3d27" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">mainWindow = new BrowserWindow({</span><span id="fbec" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  width: 1024,</span><span id="6b2f" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  height: 728,</span><span id="5db9" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  webPreferences: {</span><span id="2f2b" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">   nodeIntegration: true,</span><span id="cda4" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">   preload: path.join(__dirname, 'app/views/js/preload.js')</span><span id="4ff4" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">  }</span><span id="991d" class="oa nf dx aq nz b ea oe of og oh oi oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-bottom: -0.09em; white-space: pre-wrap; margin-top: 1.41em;">});</span>
		

And in your React App, you can require it as such:

<span id="1641" class="oa nf dx aq nz b ea ob oc l od" style="font-weight: 400; display: block; font-style: normal; color: rgba(0, 0, 0, 0.84); font-size: 16px; letter-spacing: -0.022em; font-family: Menlo, Monaco, 'Courier New', Courier, monospace; line-height: 1.18; margin-top: -0.09em; margin-bottom: -0.09em; white-space: pre-wrap;">const { ipcRenderer } = window.require("electron");</span>
		

Other Potential Trouble

React app forbids accessing files outside of src. Most of the solutions I found online involve ejecting the React app and disabling that rule in webpack.

But in our use case, we only needed the images to display in React, so we stored the image as base64 format to bypass this problem.


Conclusion

Thanks to those who have created tutorials and posts about Electron. Your contribution made learning Electron less daunting.