fix(window): renderer path off-by-one; use 'close' for state save

Two related bugs in src/main/window/index.js:

1. Renderer path was ../../dist/renderer/index.html which resolves to
   src/dist/renderer/index.html (one level too deep). Production builds
   load from <project>/dist/renderer/index.html. Fix: ../../..

   This was never caught because dev mode uses VITE_DEV_SERVER_URL and
   never touches the file path; only 'electron .' (no Vite) hits it.

2. win.on('closed', state.save) calls win.getBounds() on a destroyed
   BrowserWindow. The 'closed' event fires AFTER destruction, so
   getBounds() throws 'Object has been destroyed'. Use 'close' (fires
   before destruction) and guard with isDestroyed() as a belt-and-suspenders.

Both bugs surfaced when the user clicked File → Open. The renderer
loaded a missing HTML (blank body); the openFile handler then triggered
the closed-event state save which threw.
This commit is contained in:
2026-06-06 22:42:54 +05:30
parent f36d918871
commit 09d9f6bdd1
+5 -3
View File
@@ -38,7 +38,7 @@ function createMainWindow() {
} else { } else {
const rendererIndex = app.isPackaged const rendererIndex = app.isPackaged
? path.join(process.resourcesPath, 'renderer', 'index.html') ? path.join(process.resourcesPath, 'renderer', 'index.html')
: path.join(__dirname, '../../dist/renderer/index.html'); : path.join(__dirname, '../../../dist/renderer/index.html');
if (app.isPackaged) { if (app.isPackaged) {
try { try {
@@ -63,8 +63,10 @@ function createMainWindow() {
menu.register(win); menu.register(win);
win.on('closed', () => { // Use 'close' (fires before destruction) — 'closed' fires after the
state.save(win); // BrowserWindow object is destroyed, so getBounds() would throw.
win.on('close', () => {
if (!win.isDestroyed()) state.save(win);
}); });
// Spell check context menu // Spell check context menu