Creating Electron Installer for Both Mac Os and Windows
So you have created up a great looking Electron-based app. Now you want to create an installer for it, There is a lot of articles that can help you, but in this, I am going to share my story of how I did it, and it is also for the people who are using electron and react together.
Now you need to understand 2 things, there is no way of doing it the easy way, like there is no one-click installer creator in electron that you can use, that cover all the 100% of the cases for you, some will expose your app source, or you will end up have a gigantic size of package app and will end up having your whole project including node module in the app source code, that is not what I want.
So how we do it, 2 steps for each platform, and I am going to share my journey of windows and mac platform. First is step is making a package, and the second step will be making of an Installer.
1️⃣First Step
Install 💻electron-packager
as devdependency.
Creating a package is pretty simple, but if you have a complex project will a lot of modules, you need to configure this manually.
First thing you need to move all your project-related node_modules to dev dependency, you heard me right, You need to move all your node_modules to dev Dependency except those are being used in your node_proccess. So if you have used axios
let's say, you have to leave it on dependencies section inside node_modules. WHY? The reason is when you run electron-packager, it will going to move all your source code, including node_modules’ dependencies inside of the packaged app, which will dramatically increase the size of the app. So only leave dependencies that are using inside of main.js and move others as devDepencies.
Then create an empty file name it electron-packager and copy this into it.
var packager = require("electron-packager");
var options = {
arch: "x64",
platform: process.platform,// this will automatically select darwin if darwin or win32 if win32
dir: "./", // which directory to pack
"app-copyright": "",// fill this
"app-version": "0.0.1",
asar: true, // this will archive your source code.
icon: "./logo.ico",
name: "", // fill this
ignore: [
// list every thing that need to be ignore, so reference every single director and leave the build of the app and the files that are being used in the node module.
],
out: "./build/releases",
overwrite: true, // will overwrite whatever it might have written before.
prune: true,
version: "0.0.1",
"version-string": {
CompanyName: "",// fill this
FileDescription:
"" /*This is what display windows on task manager, shortcut and process*/,
OriginalFilename: "",// fill this
ProductName: "",// fill this
InternalName: "",// fill this
},
};
packager(options, function done_callback(err, appPaths) {
console.log(err);
console.log(appPaths);
});
The above code is self-explanatory, and after pasting the above code, you need to run node electron
in the terminal. You will get a for a folder called to build, and inside of it, you will have the release folder with your app packaged inside.
You need to make sure to ignore all the files that you don't want to expose, so if for example if I am using static react site, I need to ignore the src folder, otherwise my code will be exposed to the world, and I don't want that.
2️⃣Second Step
For mac, you need to install💻 electron-installer-dmg
For Window, you need to install💻 electron-installer-windows
for Windows 👇
electron-installer-windows --src pathto/packaged_app_folder/ --icon logo.ico --dest build/releases/
for Osx 👇
electron-installer-dmg ./path_to_packaged_app_folder/your_app.app name_of_the_installer --overwrite
You can now run any of the above commands in the terminal, and it creates you an installer for the app.
Bonus
To create a shortcut for the app, you need to install electron-squirrel-startup
. It would be best if you had this piece of code in the main js.
function handleSquirrelEvent() {
if (process.argv.length === 1) {
return false;
}const ChildProcess = require("child_process");
const path = require("path");const appFolder = path.resolve(process.execPath, "..");
const rootAtomFolder = path.resolve(appFolder, "..");
const updateDotExe = path.resolve(path.join(rootAtomFolder, "Update.exe"));
const exeName = path.basename(process.execPath);const spawn = function (command, args) {
let spawnedProcess, error;try {
spawnedProcess = ChildProcess.spawn(command, args, { detached: true });
} catch (error) {}return spawnedProcess;
};const spawnUpdate = function (args) {
return spawn(updateDotExe, args);
};const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case "--squirrel-install":
case "--squirrel-updated":
// Optionally do things such as:
// - Add your .exe to the PATH
// - Write to the registry for things like file associations and
// explorer context menus// Install desktop and start menu shortcuts
spawnUpdate(["--createShortcut", exeName]);setTimeout(app.quit, 1000);
return true;case "--squirrel-uninstall":
// Undo anything you did in the --squirrel-install and
// --squirrel-updated handlers// Remove desktop and start menu shortcuts
spawnUpdate(["--removeShortcut", exeName]);setTimeout(app.quit, 1000);
return true;case "--squirrel-obsolete":
// This is called on the outgoing version of your app before
// we update to the new version - it's the opposite of
// --squirrel-updatedapp.quit();
return true;
}
}if (handleSquirrelEvent()) {
// squirrel event handled and app will exit in 1000ms, so don't do anything else
return;
}
This will do the rest for you.
🔴 There will be one more problem that you are going to face; it will be the FILE protocol path within your app. After packing your app will not be in a compressed file because of asar. Here is an example of how I fix this problem.
const preloadLink = () => {
return isDev
? process.platform == "darwin"
? "file:///" + path.resolve(`./src/utils/${preload}.js`)
: "" + path.resolve(`./src/utils/${preload}.js`)
: window.location.href.split("/").slice(0, -2).join("/") +
`/src/utils/${preload}.js`;
};
Anyways, that is it for today. 🏃♀️
Thank you for reading this short article. I hope you found it useful.