Application Packaging
The template that we used when creating our product electron-react-boilerplate
used electron-builder
to generate a bundled version of the code for windows based systems using the nsis
format using the npm run package
command. Although this packaging did work out-of-the-box for our product, the nsis
installer did not seem to function correctly, only generating the uninstaller and not unpacking any other files. Therefore, we decided to zip the folder containing the contents to be unpacked by the installer and send that as our final product instead.
The external files related to our code were stored in a single resources directory as shown below. The ai models and openvino library files are stored under AiResources
, the database files such as the images, audio, particles and songData are all stored under Assets
. The ffmpeg
contains the executables that the node library called by electron uses to convert the audio files, cppVer.exe
is the C++ AI code compiled, SD.exe
is the python AI code compiled and yt-dlp.exe
is used by the youtube downloader module under node.
resources/
├── AiResources/
│ ├── distil-whisper-large-v3-int8/
│ ├── gemma-2-9b-it-int4-ov/
│ ├── openvino_2025/
│ ├── sdxs-512-dreamshaper/
│ ├── .python-version
│ ├── log.txt
│ ├── output.json
│ └── AiParticleList.json
├── assets/
│ ├── albumArt/
│ ├── audio/
│ ├── icons/
│ ├── images/
│ ├── lyrics/
│ ├── particles/
│ ├── shader/
│ ├── songData/
│ ├── assets.d.ts
│ ├── entitlements.mac.plist
│ ├── icon.icns
│ ├── icon.ico
│ ├── icon.png
│ ├── icon.svg
│ ├── IntelLogo.png
│ ├── MILogo.png
│ ├── NASLogo.png
│ └── UCLLogo.png
├── ffmpeg/
├── cppVer.exe
├── SD.exe
└── yt-dlp.exe
Resource Structure
Under package.json
the build field specified the options to be sent to electron-builder
when packaging the product and the resources
directory was stored as an extraResources
field, being bundled in the final application. The asar
format was used to concatenate the application files into one large files, to prevent issues with long windows paths and speed the code slightly up, with the exception of a few node modules which required to be unpackaged to work correctly.
"build": {
"productName": "SuperHappySpace",
"asar": true,
"asarUnpack": [
"**\\*.{node,dll}",
"**/node_modules/sqlite3/**/*",
"**/node_modules/node-aead-crypto/**/*",
"**/node_modules/node-dtls-client/**/*"
],
// other settings
"extraResources": [
"electron-builder.env",
{
"from": "release/app/node_modules",
"to": "node_modules"
},
{
"from": "./resources",
"to": "./",
"filter": [
"**/*"
]
}
]
}
Due to electron-builder
changing the local file locations and as the __dirname
location changes to the AppData
directory when running as a packaged application, a separate processing logic was introduced to change the reference location based on whether the app is packaged or not. Migrating all of the previous code to this format took a significant amount of time to locate all the paths but has been changed and adapted.
const path = require('path');
const { app } = require('electron');
function getResourcePath(...subPath: string[]): string {
if (app.isPackaged) {
return path.join(process.resourcesPath, ...subPath);
} else {
return path.join(app.getAppPath(),"resources", ...subPath);
}
}
const mainPaths = {
llmWhisperPath: getResourcePath('cppVer.exe'),
SDPath: getResourcePath('SD.exe'),
ps1Path: getResourcePath('AiResources', 'openvino_2025', 'setupvars.ps1'),
ffmpegPath: getResourcePath('ffmpeg', 'bin', 'ffmpeg.exe'),
ffprobePath: getResourcePath('ffmpeg', 'bin', 'ffprobe.exe'),
}
// export mainPaths and getResourcePath
export { mainPaths, getResourcePath };