How and why I built a cross platform desktop app for archive management with Electron and ReactJS
About me
I am a Computer Science and Networking engineer passionated by Software Engineering. I have been working for more than three years now at Bara Technologies Canada, helping to build enterprise software.
The problem I wanted to solve
I wanted to build a cross platform desktop app with decent design in a very short amount of time
What is a cross platform desktop app for archive management?
The application Archy is a simple desktop application to be used by an archive manager, The application goals are:
- register boxes of documents (with the name, added date, the name of the creator or owner)
- add and remove documents to each box
- handle the borrow process for the boxes (change the status of the box, if it's present, borrowed, or if the return date is passed) with the registration of the borrower with his personal details(phone number, email)
- have desktop notifications for the archive manager when a borrowed box has passed his return date
Tech stack
With the time constraints , i wanted a tech stack that could allow me to build the application really quickly and handle the cross platform aspect. I ended up choosing Electron with Reactjs.
To avoid a good amount of bugs, i chose to use typescript and for the state management, i wanted something very simple and efficient so i chose ZustandJs. For styling, since the application wasn't very large, i chose to use plain css inside components with the styled-components Css in Js library. Finally, for application storage, i also wanted something simple since all the application was going to store is plain text so i used localStorage
The process of building a cross platform desktop app for archive management
I proceeded in three key steps:
- initial setup of the application to be able to have react-fast-refresh , working correctly with create-react-app and Electron/typescript with these steps
..1. Create a base react app project
npx create-react-app <app-name> --typescript && cd <app-name>
..2. install a few packages to setup react-fast-refresh
yarn add customize-cra customize-cra-react-refresh react-app-rewired
..3. Change the react scripts in the package.json file
..4. Add electron and related packages"start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject",
yarn add cross-env electron-is-dev yarn add --dev concurrently electron electron-builder wait-on
..5. Create the electron.js file inside the public folder with this content
const electron = require('electron');
const app = electron.app;
const { Notification, BrowserWindow, ipcMain } = electron
const path = require('path');
// const url = require('url');
const isDev = require('electron-is-dev');
let mainWindow;
const sendNotification = (data) => {
console.log(data)
let iconAddress = path.join(__dirname, '/icon.png');
const notif={
title: data.title,
body: data.body,
icon: iconAddress
};
new Notification(notif).show();
}
function createWindow() {
mainWindow = new BrowserWindow(
{
width: 1280,
height: 720,
minWidth: 1280,
minHeight: 720,
backgroundColor: "#1A202C",
show: false,
webPreferences: {
worldSafeExecuteJavaScript: true,
nodeIntegration: true
}
}
);
mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`);
mainWindow.once("ready-to-show", () => mainWindow.show())
mainWindow.on('closed', () => mainWindow = null);
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
..6. Edit the package.json file
"description": "<your project description>",
"author": "<author of app>",
"build": {
"appId": "<com.your_app>"
},
"main": "public/electron.js",
"homepage": "./",
..7 add the scripts for electron
"electron-dev": "concurrently \"BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electron
.\"",
"preelectron-pack": "yarn build"
- setup the build process of the executables for the different platforms(macOS, Windows and linux) by adding a script in package.json
"electron-pack": "electron-builder -mw -c.extraMetadata.main=build/electron.js",
- build the application
Challenges I faced
There were quite a few hurdles i wasn't expecting when starting this project. Mainly, the setup process was not very well documented and the resources i managed to find where not up to date. Other than that i also faced compatibility issues when trying to integrate a custom datepicker web component in the project but the problem was mainly with the way react works and not electron itself
Key learnings
I learned that although i had my doubts about the stack, it is quite possible to build a performant cross platform application with web technologies.
Tips and advice
- Use the right tool for the job at hand
- for large lists manipulations or event displaying, use react-virtualized with react or the alternative for other frameworks to reduced the sized of the dom Nodes in memory and their processign too on the users computers
- Even when building a desktop application with web technologies, one should still consider the bundle size of the application because all the javascript will be loaded to the page and if the application is not built carefully, the app will still feal slow and janky