Skip to content

Instantly share code, notes, and snippets.

@c33k
Created March 20, 2021 16:22
Show Gist options
  • Save c33k/5ea86ea0fabc96758fc67e4d3fddf802 to your computer and use it in GitHub Desktop.
Save c33k/5ea86ea0fabc96758fc67e4d3fddf802 to your computer and use it in GitHub Desktop.
ADD ELECTRON TO CREATE-REACT-APP

1 - After creating your project with create-react-app, run: yarn add --dev electron

2 - create src/electron-start.js file and add this:

const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
    // Create the browser window.
    mainWindow = new BrowserWindow({width: 800, height: 600});

    // and load the index.html of the app.
    mainWindow.loadURL('http://localhost:3000');

    // Open the DevTools.
    mainWindow.webContents.openDevTools();

    // Emitted when the window is closed.
    mainWindow.on('closed', function () {
        // 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
    })
}

// 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', function () {
    // 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', function () {
    // 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()
    }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

This will be used to load our electron window, which will open the content server on http://localhost:3000.

3 - Add this line to your package.json:

"main": "src/electron-start.js",

4 - Add this script to your package.json

"electron": "electron ."

Now you can run your app running: yarn start and then: yarn electron

5 - Now you can modify src/electron-start.js to load the URL from a .env file:

const electron = require('electron');
const path = require('path');
const url = require('url');

const startUrl = process.env.START_URL || url.format({
    pathname: path.join(__dirname, '/../build/index.html'),
    protocol: 'file:',
    slashes: true,
});

// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow = null;

function createWindow() {
    // Create the browser window.
    mainWindow = new BrowserWindow({width: 1024, height: 768});

    // and load the index.html of the app.
    mainWindow.loadURL(startUrl);

    // Open the DevTools.
    mainWindow.webContents.openDevTools();

    // Emitted when the window is closed.
    mainWindow.on('closed', function () {
        // 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
    })
}

// 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', function () {
    // 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', function () {
    // 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()
    }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

6 - There is a problem with this: create-react-app (by default) builds an index.html that uses absolute paths. This will fail when loading it in Electron. Thankfully, there is a config option to change this: set a homepage property in package.json.

"homepage": "./",

7 - install Foreman:

yarn add --dev foreman

8 - create .env file on the same level as package.json with this content:

START_URL=http://localhost:5000

9 - Create a Procfile at the same level with this content:

react: yarn start-react
electron: node electron-wait-react

10 - modify your package.json stripts to be like this:

"scripts": {
    "start": "nf start",
    "start-react": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "start-electron": "electron ."
  }

11 - Notice that our Procfile is using a file called electron-wait-react.js. Add this file on the root of the project with the content bellow:

const net = require('net');

// Foreman offsets the port number by 100 for processes
// of different types. That's why we subtract 100 here...
const port = process.env.PORT ? (process.env.PORT - 100) : 3000;

process.env.SMOK_START_URL = `http://localhost:${port}`;

const client = new net.Socket();

let startedElectron = false;
const tryConnection = () => client.connect({port: port}, () => {
        client.end();
        if(!startedElectron) {
            console.log('starting electron');
            startedElectron = true;
            const exec = require('child_process').exec;
            exec('yarn start-electron');
        }
    }
);

tryConnection();

client.on('error', (error) => {
    setTimeout(tryConnection, 1000);
});

12 - Now we can basically run the project with the command:

yarn start

Reference post: https://www.freecodecamp.org/news/building-an-electron-application-with-create-react-app-97945861647c/#:~:text=a%20great%20tool.-,Electron%20and,is%20Facebook's%20JavaScript%20view%20framework.&text=And%20Electron%20is%20GitHub's%20framework,platform%20desktop%20apps%20in%20JavaScript.&text=Most%20use%20webpack%20for%20the%20configuration%20necessary%20for%20React%20development.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment