forked from imbytecat/fullstack-starter
feat(desktop): show native error dialogs on startup failures
Replace silent console.error + app.quit() with dialog.showErrorBox() so users actually see why the app failed to start instead of it just disappearing. Covers server spawn errors, timeout, port allocation failure, mid-session server crashes, and window creation failures.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import { createServer } from 'node:net'
|
||||
import { join } from 'node:path'
|
||||
import { app, BrowserWindow, shell } from 'electron'
|
||||
import { app, BrowserWindow, dialog, shell } from 'electron'
|
||||
import killProcessTree from 'tree-kill'
|
||||
|
||||
const DEV_SERVER_URL = 'http://localhost:3000'
|
||||
@@ -9,10 +9,17 @@ const DEV_SERVER_URL = 'http://localhost:3000'
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
let serverProcess: ReturnType<typeof spawn> | null = null
|
||||
let isQuitting = false
|
||||
let serverReady = false
|
||||
|
||||
const shouldAbortWindowLoad = (): boolean =>
|
||||
isQuitting || !mainWindow || mainWindow.isDestroyed()
|
||||
|
||||
const showErrorAndQuit = (title: string, detail: string) => {
|
||||
if (isQuitting) return
|
||||
dialog.showErrorBox(title, detail)
|
||||
app.quit()
|
||||
}
|
||||
|
||||
const getAvailablePort = (): Promise<number> =>
|
||||
new Promise((resolve, reject) => {
|
||||
const server = createServer()
|
||||
@@ -84,10 +91,22 @@ const spawnServer = (port: number): string => {
|
||||
|
||||
serverProcess.on('error', (err) => {
|
||||
console.error('Failed to start server:', err)
|
||||
showErrorAndQuit(
|
||||
'Startup Failed',
|
||||
'A required component failed to start. Please reinstall the app.',
|
||||
)
|
||||
})
|
||||
|
||||
serverProcess.on('exit', () => {
|
||||
serverProcess.on('exit', (code) => {
|
||||
serverProcess = null
|
||||
if (!isQuitting && serverReady) {
|
||||
showErrorAndQuit(
|
||||
'Service Stopped',
|
||||
app.isPackaged
|
||||
? 'The background service stopped unexpectedly. Please restart the app.'
|
||||
: `Server process exited unexpectedly (code ${code}). Check the server logs for details.`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return `http://127.0.0.1:${port}`
|
||||
@@ -98,7 +117,16 @@ const resolveServerUrl = async (): Promise<string | null> => {
|
||||
return DEV_SERVER_URL
|
||||
}
|
||||
|
||||
const port = await getAvailablePort()
|
||||
let port: number
|
||||
try {
|
||||
port = await getAvailablePort()
|
||||
} catch {
|
||||
showErrorAndQuit(
|
||||
'Startup Failed',
|
||||
"The app couldn't allocate a local port. Please close other apps and try again.",
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
if (isQuitting) {
|
||||
return null
|
||||
@@ -148,15 +176,16 @@ const createWindow = async () => {
|
||||
}
|
||||
|
||||
if (!ready) {
|
||||
console.error(
|
||||
showErrorAndQuit(
|
||||
'Startup Failed',
|
||||
app.isPackaged
|
||||
? 'Server binary did not start in time.'
|
||||
? 'The app is taking too long to start. Please try again.'
|
||||
: 'Dev server not responding. Run `bun dev` in apps/server first.',
|
||||
)
|
||||
app.quit()
|
||||
return
|
||||
}
|
||||
|
||||
serverReady = true
|
||||
mainWindow.loadURL(serverUrl)
|
||||
}
|
||||
|
||||
@@ -170,7 +199,12 @@ app
|
||||
.then(createWindow)
|
||||
.catch((e) => {
|
||||
console.error('Failed to create window:', e)
|
||||
app.quit()
|
||||
showErrorAndQuit(
|
||||
"App Couldn't Start",
|
||||
app.isPackaged
|
||||
? "We couldn't open the application window. Please restart your computer and try again."
|
||||
: `Failed to create window: ${e instanceof Error ? e.message : String(e)}`,
|
||||
)
|
||||
})
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
@@ -182,7 +216,15 @@ app.on('window-all-closed', () => {
|
||||
|
||||
app.on('activate', () => {
|
||||
if (!isQuitting && BrowserWindow.getAllWindows().length === 0) {
|
||||
createWindow()
|
||||
createWindow().catch((e) => {
|
||||
console.error('Failed to re-create window:', e)
|
||||
showErrorAndQuit(
|
||||
"App Couldn't Start",
|
||||
app.isPackaged
|
||||
? "We couldn't open the application window. Please restart the app."
|
||||
: `Failed to re-create window: ${e instanceof Error ? e.message : String(e)}`,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user