mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-20 13:53:32 +08:00
fix(desktop): reveal renderer startup failures (#1032)
This commit is contained in:
parent
e72020247b
commit
26e863902f
@ -1,10 +1,10 @@
|
||||
import { app, BrowserWindow, clipboard, ipcMain, Notification, screen, session, WebContentsView } from 'electron'
|
||||
import { app, BrowserWindow, clipboard, dialog, ipcMain, Notification, screen, session, WebContentsView } from 'electron'
|
||||
import { autoUpdater } from 'electron-updater'
|
||||
import path from 'node:path'
|
||||
import { ELECTRON_EVENT_CHANNELS, ELECTRON_INTERNAL_CHANNELS, ELECTRON_IPC_CHANNELS, type ElectronIpcChannel } from './ipc/channels'
|
||||
import { isElectronIpcChannel, validateElectronIpcPayload } from './ipc/capabilities'
|
||||
import { ElectronServerRuntime } from './services/serverRuntime'
|
||||
import { electronHostDiagnosticsFile } from './services/sidecarManager'
|
||||
import { electronHostDiagnosticsFile, sanitizeHostDiagnostic } from './services/sidecarManager'
|
||||
import { openDialog, saveDialog } from './services/dialogs'
|
||||
import { openExternalUrl, openSystemPath, openSystemSettingsUrl } from './services/shell'
|
||||
import {
|
||||
@ -38,6 +38,7 @@ import { logNotificationSmokeRendererAck, scheduleNotificationSmoke } from './se
|
||||
import { normalizeZoomFactor } from './services/zoom'
|
||||
import { resolveRendererEntry } from './services/rendererEntry'
|
||||
import { writeWindowSmokeSnapshot } from './services/windowSmoke'
|
||||
import { loadAndRevealMainWindow } from './services/windowStartup'
|
||||
import {
|
||||
installWindowLifecycle,
|
||||
readWindowState,
|
||||
@ -410,10 +411,20 @@ async function createMainWindow() {
|
||||
|
||||
writeWindowSmokeSnapshot(mainWindow, 'after-create')
|
||||
|
||||
await loadRendererEntry(mainWindow)
|
||||
|
||||
restoreWindowMaximized(mainWindow, restoredState)
|
||||
showMainWindow(mainWindow, app)
|
||||
await loadAndRevealMainWindow({
|
||||
load: () => loadRendererEntry(mainWindow!),
|
||||
beforeReveal: () => restoreWindowMaximized(mainWindow!, restoredState),
|
||||
reveal: () => showMainWindow(mainWindow, app),
|
||||
onLoadFailure: (error) => {
|
||||
const detail = sanitizeHostDiagnostic(error instanceof Error ? error.message : String(error))
|
||||
console.error(`[desktop] failed to load Electron renderer: ${detail}`)
|
||||
writeWindowSmokeSnapshot(mainWindow, 'renderer-load-failed')
|
||||
dialog.showErrorBox(
|
||||
'启动错误 / Startup Error',
|
||||
`桌面界面加载失败,请重启应用。如果问题持续存在,请附上诊断日志反馈。\n\nThe desktop interface could not be loaded. Restart the app and include diagnostics when reporting the problem.\n\n${detail}`,
|
||||
)
|
||||
},
|
||||
})
|
||||
refreshWindowsDragHitTest(mainWindow, process.platform)
|
||||
writeWindowSmokeSnapshot(mainWindow, 'after-final-show')
|
||||
}
|
||||
|
||||
57
desktop/electron/services/windowStartup.test.ts
Normal file
57
desktop/electron/services/windowStartup.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { loadAndRevealMainWindow } from './windowStartup'
|
||||
|
||||
describe('Electron main window startup', () => {
|
||||
it('reveals the main window after the renderer loads', async () => {
|
||||
const order: string[] = []
|
||||
const onLoadFailure = vi.fn()
|
||||
|
||||
const result = await loadAndRevealMainWindow({
|
||||
load: async () => { order.push('load') },
|
||||
beforeReveal: () => { order.push('before-reveal') },
|
||||
reveal: () => { order.push('reveal') },
|
||||
onLoadFailure,
|
||||
})
|
||||
|
||||
expect(result).toEqual({ loaded: true })
|
||||
expect(order).toEqual(['load', 'before-reveal', 'reveal'])
|
||||
expect(onLoadFailure).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('still reveals the main window and reports the error when renderer loading fails', async () => {
|
||||
const order: string[] = []
|
||||
const failure = new Error('renderer entry unavailable')
|
||||
|
||||
const result = await loadAndRevealMainWindow({
|
||||
load: async () => {
|
||||
order.push('load')
|
||||
throw failure
|
||||
},
|
||||
beforeReveal: () => { order.push('before-reveal') },
|
||||
reveal: () => { order.push('reveal') },
|
||||
onLoadFailure: (error) => {
|
||||
expect(error).toBe(failure)
|
||||
order.push('failure')
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toEqual({ loaded: false, error: failure })
|
||||
expect(order).toEqual(['load', 'before-reveal', 'reveal', 'failure'])
|
||||
})
|
||||
|
||||
it('treats an undefined rejection as a load failure', async () => {
|
||||
const reveal = vi.fn()
|
||||
const onLoadFailure = vi.fn()
|
||||
|
||||
const result = await loadAndRevealMainWindow({
|
||||
load: () => Promise.reject(undefined),
|
||||
beforeReveal: vi.fn(),
|
||||
reveal,
|
||||
onLoadFailure,
|
||||
})
|
||||
|
||||
expect(result).toEqual({ loaded: false, error: undefined })
|
||||
expect(reveal).toHaveBeenCalledTimes(1)
|
||||
expect(onLoadFailure).toHaveBeenCalledWith(undefined)
|
||||
})
|
||||
})
|
||||
35
desktop/electron/services/windowStartup.ts
Normal file
35
desktop/electron/services/windowStartup.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export type MainWindowStartupOptions = {
|
||||
load: () => Promise<void>
|
||||
beforeReveal: () => void
|
||||
reveal: () => void
|
||||
onLoadFailure: (error: unknown) => void
|
||||
}
|
||||
|
||||
export type MainWindowStartupResult =
|
||||
| { loaded: true }
|
||||
| { loaded: false, error: unknown }
|
||||
|
||||
export async function loadAndRevealMainWindow({
|
||||
load,
|
||||
beforeReveal,
|
||||
reveal,
|
||||
onLoadFailure,
|
||||
}: MainWindowStartupOptions): Promise<MainWindowStartupResult> {
|
||||
let loaded = true
|
||||
let loadError: unknown
|
||||
try {
|
||||
await load()
|
||||
} catch (error) {
|
||||
loaded = false
|
||||
loadError = error
|
||||
}
|
||||
|
||||
beforeReveal()
|
||||
reveal()
|
||||
|
||||
if (!loaded) {
|
||||
onLoadFailure(loadError)
|
||||
return { loaded: false, error: loadError }
|
||||
}
|
||||
return { loaded: true }
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user