Skip to main content

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 };