Electron build / release pipeline — fix log
The first attempted release (v0.1.0) failed in CI because the Windows
installer step couldn't satisfy electron-builder's asar sanity check:
⨯ Application entry file "src\js\main_electron.js" in the
"...\dist\win-unpacked\resources\app.asar" does not exist.
That single error masks several compounding misconfigurations. This doc records all of them so the fix branch (and any future regression) has a clear reference.
Bug 1 — files glob matches nothing
In frontend/package.json:
"build": {
"files": [
"frontend/**/*",
"main_electron.js",
"preload.cjs"
]
}
electron-builder runs from working-directory: frontend (set in
.github/workflows/release.yml), so:
frontend/**/*resolves tofrontend/frontend/**/*— no matches.main_electron.jsandpreload.cjsare looked up at the package root (frontend/), but they actually live atfrontend/src/js/main_electron.jsandfrontend/src/js/preload.cjs.
Net effect: nothing in src/ reaches the asar, the main entry
points at a missing file, and the sanity check fails.
Fix. Replace with a glob that's relative to the package root:
"files": [
"src/**/*",
"package.json"
]
Bug 2 — production page-load path is wrong
frontend/src/js/main_electron.js line 136:
win.loadFile(path.join(__dirname, 'dist', 'index.html'));
__dirname of the main file inside the asar is <asar>/src/js/, so
this resolves to <asar>/src/js/dist/index.html — but Vite outputs
to frontend/dist/, one level above src/. Even with Bug 1 fixed,
the packaged app would launch a white window because the renderer
HTML isn't where the main process is looking.
Fix. Use app.getAppPath() (the asar root) and add the Vite
output to the files glob so dist/ ends up inside the asar:
const appRoot = app.getAppPath(); // <asar> root
win.loadFile(path.join(appRoot, 'dist', 'index.html'));
"files": [
"src/**/*",
"dist/**/*",
"package.json"
]
Bug 3 — Vite and electron-builder share frontend/dist/
vite.config.js:
build: { outDir: '../dist' } // → frontend/dist/
…and electron-builder's default output is also dist/ relative to
the project root (i.e. frontend/dist/). The CI sequence is:
npm run build→ Vite writes the renderer bundle tofrontend/dist/.npm run dist→ electron-builder cleans and reusesfrontend/dist/for the installer +win-unpacked/.
The two clobber each other, which is why the installer artifact ends up there but the renderer bundle inside the asar can be incomplete.
Fix. Give electron-builder its own output directory and update
the upload + release paths in release.yml:
"directories": {
"buildResources": "assets",
"output": "dist-electron"
}
- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: EdgeWeave-windows-installer
path: frontend/dist-electron/*.exe
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: frontend/dist-electron/*.exe
frontend/dist/ is then exclusively the Vite output and gets bundled
into the asar via the files glob from Bug 2's fix.
Bug 5 — empty description warning
electron-builder logs:
description is missed in the package.json
Cosmetic, but it ends up on the installer's "About" panel and in the NSIS metadata, so worth filling in. Resolved upstream by the user.
Bug 4 — backend + Python aren't packaged at all (resolved — see python-electron-bundling)
frontend/src/js/main_electron.js resolves the worker process from
process.resourcesPath:
const pythonPath = isWin
? path.join(process.resourcesPath, 'python', 'python.exe')
: path.join(process.resourcesPath, 'python', 'bin', 'python3');
const backendDir = path.join(process.resourcesPath, 'backend');
Neither python/ nor backend/ is currently copied into
process.resourcesPath by the installer — there's no
extraResources block in the build config. Even after Bugs 1–3 are
resolved, the packaged .exe will launch its window but fail to
start the worker subprocess.
Resolved in a separate PR — see python-electron-bundling for the full design rationale. Decisions taken:
- Python runtime:
python-build-standalone(PBS)install_onlytarballs, downloaded at CI time and cached. Chosen over the embedded distribution and PyInstaller because PBS ships a complete, relocatable CPython with stdlib intact (nopython311.zipweirdness) and works identically across Win/Mac/Linux. - Dependencies: vendored at build time via
pip install --target backend/_vendor -r backend/requirements.txt, surfaced to the interpreter at runtime by inserting_vendornear the top ofsys.pathinbackend/fastapi_main.py. No first-launch pip step on the user's machine. - Spawn environment:
main_electron.jsclears any inheritedPYTHONHOME(which would break PBS's relocatability) and setsPYTHONPATH=<resources>/backend/_vendor. We also setPYTHONDONTWRITEBYTECODE=1so the read-only resource tree isn't scribbled with.pycfiles. - Cross-platform parity: the same shape works on all three OSes;
only the PBS download URL and the
python.exevsbin/python3path fork. CI currently builds the Windows installer; macOS/Linux jobs follow the same recipe.
The implementing changes are:
"extraResources": [
{ "from": "../backend", "to": "backend",
"filter": ["**/*", "!**/__pycache__/**", "!tests/**", ...] },
{ "from": "python-portable", "to": "python" }
]
- name: Download & extract python-build-standalone (Windows x86_64)
run: |
curl -fsSL -o pbs.tar.gz "${URL}"
tar -xzf pbs.tar.gz
mv python python-portable
- name: Vendor backend dependencies into _vendor
run: |
./python-portable/python.exe -m pip install \
--target ../backend/_vendor --no-compile \
-r ../backend/requirements.txt
Recommended commit / PR shape for the fix branch
One commit per bug, with clear subjects, all on a single
fix/electron-build branch off dev:
fix(build): correct files glob in package.json (Bug 1)fix(electron): use app.getAppPath() for renderer load (Bug 2)fix(build): give electron-builder its own output dir (Bug 3)chore: update release.yml paths after Bug 3
The description already added by the user (Bug 5) belongs in its
own commit too if it's not already merged.
What this PR does not fix
Bug 4 (backend / Python bundling) — resolved by the follow-up
branch documented in
python-electron-bundling. The
installer now ships a relocatable CPython under <resources>/python/
and the backend tree under <resources>/backend/ (with vendored deps
in _vendor/). Renderer + backend should both come up on a clean
Windows machine without any system Python install.
The full design discussion for Bug 4 — python-build-standalone
choice, extraResources block, vendoring strategy, signing /
notarization caveats — lives in
python-electron-bundling.