mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/mihomo-party-org/clash-party.git
synced 2026-09-20 08:03:39 +08:00
fix: recover main window when renderer process crashes
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
|
||||
- 机场插件机制,服务商请参考: [`docs/plugin/机场服务端对接指南-v2.md`](../../docs/plugin/机场服务端对接指南-v2.md)
|
||||
|
||||
## 修复 (Fix)
|
||||
|
||||
- 部分场景下的白屏问题
|
||||
|
||||
# 1.9.6
|
||||
|
||||
## 新功能 (Feat)
|
||||
|
||||
@@ -101,6 +101,7 @@ export const appLogger = createLogger('app')
|
||||
|
||||
// 为了保持向后兼容性,创建各模块的日志实例(都指向同一个应用日志)
|
||||
export const floatingWindowLogger = createLogger('floating-window')
|
||||
export const mainWindowLogger = createLogger('main-window')
|
||||
export const coreLogger = createLogger('mihomo-core')
|
||||
export const apiLogger = createLogger('mihomo-api')
|
||||
export const configLogger = createLogger('config')
|
||||
|
||||
@@ -8,6 +8,7 @@ import { quitWithoutCore, stopCore } from './core/manager'
|
||||
import { triggerSysProxy } from './sys/sysproxy'
|
||||
import { hideDockIcon, showDockIcon } from './resolve/tray'
|
||||
import { dataDir } from './utils/dirs'
|
||||
import { mainWindowLogger } from './utils/logger'
|
||||
|
||||
interface WindowState {
|
||||
width: number
|
||||
@@ -53,6 +54,11 @@ function ensureVisibleOnScreen(state: WindowState): WindowState {
|
||||
export let mainWindow: BrowserWindow | null = null
|
||||
let quitTimeout: NodeJS.Timeout | null = null
|
||||
let createWindowPromise: Promise<void> | null = null
|
||||
|
||||
// 主窗口 renderer 崩溃自动恢复的防抖,避免崩溃循环时无限重建
|
||||
const MAIN_WINDOW_CRASH_WINDOW = 60 * 1000
|
||||
const MAIN_WINDOW_MAX_CRASH_RECOVERIES = 3
|
||||
let mainWindowCrashTimestamps: number[] = []
|
||||
type AutoQuitWithoutCoreMode = NonNullable<IAppConfig['autoQuitWithoutCoreMode']>
|
||||
|
||||
export async function createWindow(): Promise<void> {
|
||||
@@ -94,7 +100,8 @@ async function createWindowInternal(): Promise<void> {
|
||||
height: 49
|
||||
},
|
||||
autoHideMenuBar: true,
|
||||
...(process.platform === 'linux' ? { icon: icon } : {}),
|
||||
// Win 显式指定 icon,避免异常/恢复路径下任务栏与窗口图标依赖默认 exe
|
||||
...(process.platform === 'linux' || process.platform === 'win32' ? { icon: icon } : {}),
|
||||
webPreferences: {
|
||||
preload: join(__dirname, '../preload/index.cjs'),
|
||||
spellcheck: false,
|
||||
@@ -153,6 +160,46 @@ function setupWindowEvents(window: BrowserWindow, config: WindowConfig): void {
|
||||
window.webContents.reload()
|
||||
})
|
||||
|
||||
// renderer 崩溃时外壳仍在(isDestroyed() 为 false)、did-fail-load 不触发,会白屏;销毁并按需重建
|
||||
window.webContents.on('render-process-gone', (_event, details) => {
|
||||
mainWindowLogger.error('Main window render process gone', details.reason).catch(() => {})
|
||||
|
||||
if (mainWindow !== window || window.isDestroyed()) return
|
||||
|
||||
const wasVisible = window.isVisible()
|
||||
|
||||
mainWindow = null
|
||||
window.destroy()
|
||||
|
||||
const now = Date.now()
|
||||
mainWindowCrashTimestamps = mainWindowCrashTimestamps.filter(
|
||||
(timestamp) => now - timestamp < MAIN_WINDOW_CRASH_WINDOW
|
||||
)
|
||||
mainWindowCrashTimestamps.push(now)
|
||||
|
||||
if (mainWindowCrashTimestamps.length > MAIN_WINDOW_MAX_CRASH_RECOVERIES) {
|
||||
mainWindowLogger
|
||||
.error(
|
||||
`Main window renderer crashed ${mainWindowCrashTimestamps.length} times within ${MAIN_WINDOW_CRASH_WINDOW}ms, stop auto-recovery`
|
||||
)
|
||||
.catch(() => {})
|
||||
return
|
||||
}
|
||||
|
||||
// 可见时立即重建,否则留待下次 showMainWindow(),避免后台崩溃突然弹窗
|
||||
if (wasVisible) {
|
||||
void createWindow().then(() => {
|
||||
clearQuitTimeout()
|
||||
mainWindow?.show()
|
||||
mainWindow?.focusOnWebView()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
window.webContents.on('unresponsive', () => {
|
||||
mainWindowLogger.error('Main window unresponsive').catch(() => {})
|
||||
})
|
||||
|
||||
window.on('show', () => {
|
||||
showDockIcon()
|
||||
})
|
||||
@@ -250,6 +297,10 @@ export function showMainWindow(): void {
|
||||
|
||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||
clearQuitTimeout()
|
||||
// 兜底:renderer 已崩溃但 render-process-gone 尚未触发时,先 reload 再显示,避免白屏
|
||||
if (mainWindow.webContents.isCrashed()) {
|
||||
mainWindow.webContents.reload()
|
||||
}
|
||||
mainWindow.show()
|
||||
mainWindow.focusOnWebView()
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user