There are many ways of packaging an app, but we'll use a tool, electron-builder, that will make it even easier, if you can get its configuration right!
Let's take a look at the necessary steps. First of all, we'll have to begin by defining the build configuration, and our initial step will be, as always, to install the tool:
npm install electron-builder --save-dev
To access the added tool, we'll require a new script, which we'll add in package.json:
"scripts": {
"dist": "electron-builder",
.
.
.
}
We'll also have to add a few more details to package.json, which are needed for the build process and the produced app. In particular, the homepage change is required, because the CRA-created index.html file uses absolute paths that won't work later with Electron:
"name": "chapter13",
"version": "0.1.0",
"description": "Regions app for chapter 13",
"homepage": "./",
"license": "free",
"author": "Federico Kereki",
Finally, some specific building configuration will be required. You cannot build for macOS with a Linux or Windows machine, so I'll leave that configuration out. We have to specify where the files will be found, what compression method to use, and so on:
"build": {
"appId": "com.electron.chapter13",
"compression": "normal",
"asar": true,
"extends": null,
"files": [
"electron-start.js",
"build/**/*",
"node_modules/**/*",
"src/regionsApp/r_icon.png"
],
"linux": {
"target": "zip"
},
"win": {
"target": "portable"
}
}
We have completed the required configuration, but there are also some changes to do in the code itself, and we'll have to adapt the code for building the package. When the packaged app runs, there won't be any webpack server running; the code will be taken from the built React package. Also, you won't want to include debugging tools. So, the starter code will require the following changes:
// Source file: electron-start.for.builder.js
/* @flow */
const { app, BrowserWindow } = require("electron");
const path = require("path");
const url = require("url");
let mainWindow;
const createWindow = () => {
mainWindow = new BrowserWindow({
height: 768,
width: 1024,
icon: path.join(__dirname, "./build/r_icon.png")
});
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, "./build/index.html"),
protocol: "file",
slashes: true
})
);
mainWindow.on("closed", () => {
mainWindow = null;
});
};
app.on("ready", createWindow);
app.on("activate", () => mainWindow === null && createWindow());
app.on(
"window-all-closed",
() => process.platform !== "darwin" && app.quit()
);
Mainly, we are taking icons and code from the build/ directory. An npm run build command will take care of generating that directory, so we can proceed with creating our executable app.