Skip to content

Commit 498e190

Browse files
committed
fix(chat): add packaged freeze diagnostics
1 parent 86d2853 commit 498e190

4 files changed

Lines changed: 385 additions & 11 deletions

File tree

desktop/src/main.cjs

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,62 @@ function setupRendererConsoleLogging(win) {
13801380
});
13811381
}
13821382

1383+
function setupRendererLifecycleLogging(win) {
1384+
if (!debugEnabled()) return;
1385+
1386+
const logRendererLifecycle = (message) => {
1387+
logMain(`[renderer] ${message}`);
1388+
};
1389+
1390+
logRendererLifecycle(`window-created id=${win.id}`);
1391+
1392+
win.webContents.on("did-start-loading", () => {
1393+
logRendererLifecycle("did-start-loading");
1394+
});
1395+
1396+
win.webContents.on("dom-ready", () => {
1397+
logRendererLifecycle(`dom-ready url=${win.webContents.getURL()}`);
1398+
});
1399+
1400+
win.webContents.on("did-stop-loading", () => {
1401+
logRendererLifecycle("did-stop-loading");
1402+
});
1403+
1404+
win.webContents.on("did-finish-load", () => {
1405+
logRendererLifecycle(`did-finish-load url=${win.webContents.getURL()}`);
1406+
});
1407+
1408+
win.webContents.on("did-fail-load", (_event, errorCode, errorDescription, validatedURL, isMainFrame) => {
1409+
logRendererLifecycle(
1410+
`did-fail-load code=${errorCode} mainFrame=${!!isMainFrame} url=${validatedURL} error=${errorDescription}`
1411+
);
1412+
});
1413+
1414+
win.webContents.on("did-navigate", (_event, url, httpResponseCode, httpStatusText) => {
1415+
logRendererLifecycle(
1416+
`did-navigate url=${url} code=${httpResponseCode || 0} status=${httpStatusText || ""}`
1417+
);
1418+
});
1419+
1420+
win.webContents.on("did-navigate-in-page", (_event, url, isMainFrame) => {
1421+
logRendererLifecycle(`did-navigate-in-page mainFrame=${!!isMainFrame} url=${url}`);
1422+
});
1423+
1424+
win.webContents.on("render-process-gone", (_event, details) => {
1425+
logRendererLifecycle(
1426+
`render-process-gone reason=${details?.reason || ""} exitCode=${details?.exitCode ?? ""}`
1427+
);
1428+
});
1429+
1430+
win.on("unresponsive", () => {
1431+
logRendererLifecycle("window-unresponsive");
1432+
});
1433+
1434+
win.on("responsive", () => {
1435+
logRendererLifecycle("window-responsive");
1436+
});
1437+
}
1438+
13831439
function createMainWindow() {
13841440
const win = new BrowserWindow({
13851441
width: 1200,
@@ -1423,18 +1479,26 @@ function createMainWindow() {
14231479
});
14241480

14251481
setupRendererConsoleLogging(win);
1482+
setupRendererLifecycleLogging(win);
14261483

14271484
return win;
14281485
}
14291486

14301487
async function loadWithRetry(win, url) {
14311488
const startedAt = Date.now();
1489+
let attempt = 0;
14321490
// eslint-disable-next-line no-constant-condition
14331491
while (true) {
1492+
attempt += 1;
1493+
logMain(`[main] loadWithRetry attempt=${attempt} url=${url}`);
14341494
try {
14351495
await win.loadURL(url);
1496+
logMain(`[main] loadWithRetry success attempt=${attempt} elapsedMs=${Date.now() - startedAt} url=${url}`);
14361497
return;
1437-
} catch {
1498+
} catch (err) {
1499+
logMain(
1500+
`[main] loadWithRetry failure attempt=${attempt} elapsedMs=${Date.now() - startedAt} url=${url} error=${err?.message || err}`
1501+
);
14381502
if (Date.now() - startedAt > 60_000) throw new Error(`Failed to load URL in time: ${url}`);
14391503
await new Promise((r) => setTimeout(r, 500));
14401504
}
@@ -1502,6 +1566,15 @@ function registerWindowIpc() {
15021566
}
15031567
});
15041568

1569+
ipcMain.handle("app:isDebugEnabled", () => {
1570+
try {
1571+
return debugEnabled();
1572+
} catch (err) {
1573+
logMain(`[main] app:isDebugEnabled failed: ${err?.message || err}`);
1574+
return false;
1575+
}
1576+
});
1577+
15051578
ipcMain.handle("app:setCloseBehavior", (_event, behavior) => {
15061579
try {
15071580
const next = setCloseBehavior(behavior);
@@ -1727,6 +1800,7 @@ async function main() {
17271800
process.env.ELECTRON_START_URL ||
17281801
(app.isPackaged ? getBackendUiUrl() : "http://localhost:3000");
17291802

1803+
logMain(`[main] debugEnabled=${debugEnabled()} startUrl=${startUrl}`);
17301804
await loadWithRetry(win, startUrl);
17311805

17321806
// Auto-check updates after the UI has loaded (packaged builds only).

desktop/src/preload.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ contextBridge.exposeInMainWorld("wechatDesktop", {
77
toggleMaximize: () => ipcRenderer.invoke("window:toggleMaximize"),
88
close: () => ipcRenderer.invoke("window:close"),
99
isMaximized: () => ipcRenderer.invoke("window:isMaximized"),
10+
isDebugEnabled: () => ipcRenderer.invoke("app:isDebugEnabled"),
1011

1112
getAutoLaunch: () => ipcRenderer.invoke("app:getAutoLaunch"),
1213
setAutoLaunch: (enabled) => ipcRenderer.invoke("app:setAutoLaunch", !!enabled),

frontend/composables/chat/useChatMessages.js

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ export const useChatMessages = ({
2727
const messageContainerRef = ref(null)
2828
const activeMessagesFor = ref('')
2929
const showJumpToBottom = ref(false)
30+
let lastRenderMessagesFingerprint = ''
31+
32+
const isDesktopRenderer = () => {
33+
if (!process.client || typeof window === 'undefined') return false
34+
return !!window.wechatDesktop?.__brand
35+
}
36+
37+
const logMessagePhase = (phase, details = {}) => {
38+
if (!isDesktopRenderer()) return
39+
console.info(`[chat-messages] ${phase}`, {
40+
account: String(selectedAccount.value || '').trim(),
41+
selectedUsername: String(selectedContact.value?.username || '').trim(),
42+
activeMessagesFor: String(activeMessagesFor.value || '').trim(),
43+
...details
44+
})
45+
}
3046

3147
const previewImageUrl = ref(null)
3248
const previewVideoUrl = ref(null)
@@ -113,8 +129,16 @@ export const useChatMessages = ({
113129
const renderMessages = computed(() => {
114130
const list = messages.value || []
115131
const reverseSides = !!reverseMessageSides.value
132+
const fingerprint = `${String(selectedContact.value?.username || '').trim()}:${list.length}:${reverseSides ? '1' : '0'}`
133+
const shouldLogRender = isDesktopRenderer() && fingerprint !== lastRenderMessagesFingerprint
134+
if (shouldLogRender) {
135+
logMessagePhase('renderMessages:start', {
136+
count: list.length,
137+
reverseSides
138+
})
139+
}
116140
let previousTs = 0
117-
return list.map((message) => {
141+
const rendered = list.map((message) => {
118142
const ts = Number(message.createTime || 0)
119143
const show = !previousTs || (ts && Math.abs(ts - previousTs) >= 300)
120144
if (ts) previousTs = ts
@@ -127,6 +151,14 @@ export const useChatMessages = ({
127151
timeDivider: formatTimeDivider(ts)
128152
}
129153
})
154+
if (shouldLogRender) {
155+
lastRenderMessagesFingerprint = fingerprint
156+
logMessagePhase('renderMessages:end', {
157+
count: rendered.length,
158+
reverseSides
159+
})
160+
}
161+
return rendered
130162
})
131163

132164
const updateJumpToBottomState = () => {
@@ -333,6 +365,10 @@ export const useChatMessages = ({
333365
const loadMessages = async ({ username, reset }) => {
334366
if (!username || !selectedAccount.value) return
335367

368+
logMessagePhase('loadMessages:enter', {
369+
username,
370+
reset
371+
})
336372
messagesError.value = ''
337373
isLoadingMessages.value = true
338374
activeMessagesFor.value = username
@@ -357,13 +393,47 @@ export const useChatMessages = ({
357393
if (realtimeEnabled.value) {
358394
params.source = 'realtime'
359395
}
396+
logMessagePhase('loadMessages:request:start', {
397+
username,
398+
reset,
399+
offset,
400+
existingCount: existing.length,
401+
renderTypeFilter: messageTypeFilter.value,
402+
realtime: !!realtimeEnabled.value
403+
})
360404
const response = await api.listChatMessages(params)
405+
logMessagePhase('loadMessages:request:end', {
406+
username,
407+
reset,
408+
rawCount: Array.isArray(response?.messages) ? response.messages.length : 0,
409+
total: Number(response?.total || 0),
410+
hasMore: response?.hasMore
411+
})
361412

362413
const raw = response?.messages || []
414+
logMessagePhase('loadMessages:normalize:start', {
415+
username,
416+
rawCount: raw.length
417+
})
363418
const mapped = dedupeMessagesById(raw.map(normalizeMessage))
419+
logMessagePhase('loadMessages:normalize:end', {
420+
username,
421+
mappedCount: mapped.length
422+
})
364423

365-
if (activeMessagesFor.value !== username) return
424+
if (activeMessagesFor.value !== username) {
425+
logMessagePhase('loadMessages:abort-stale', {
426+
username,
427+
activeMessagesFor: activeMessagesFor.value
428+
})
429+
return
430+
}
366431

432+
logMessagePhase('loadMessages:state-commit:start', {
433+
username,
434+
reset,
435+
mappedCount: mapped.length
436+
})
367437
if (reset) {
368438
allMessages.value = { ...allMessages.value, [username]: mapped }
369439
} else {
@@ -380,6 +450,10 @@ export const useChatMessages = ({
380450
[username]: [...older, ...existing]
381451
}
382452
}
453+
logMessagePhase('loadMessages:state-commit:end', {
454+
username,
455+
storedCount: (allMessages.value[username] || []).length
456+
})
383457

384458
messagesMeta.value = {
385459
...messagesMeta.value,
@@ -388,8 +462,20 @@ export const useChatMessages = ({
388462
hasMore: response?.hasMore
389463
}
390464
}
465+
logMessagePhase('loadMessages:meta-commit:end', {
466+
username,
467+
total: Number(response?.total || 0),
468+
hasMore: response?.hasMore
469+
})
391470

471+
logMessagePhase('loadMessages:nextTick:start', {
472+
username
473+
})
392474
await nextTick()
475+
logMessagePhase('loadMessages:nextTick:end', {
476+
username,
477+
renderedCount: (allMessages.value[username] || []).length
478+
})
393479
const nextContainer = messageContainerRef.value
394480
if (nextContainer) {
395481
if (reset) {
@@ -400,10 +486,28 @@ export const useChatMessages = ({
400486
}
401487
}
402488
updateJumpToBottomState()
489+
logMessagePhase('loadMessages:scroll:end', {
490+
username,
491+
hasContainer: !!nextContainer,
492+
scrollTop: nextContainer ? nextContainer.scrollTop : null,
493+
scrollHeight: nextContainer ? nextContainer.scrollHeight : null
494+
})
403495
} catch (error) {
496+
console.error('[chat-messages] loadMessages:error', {
497+
account: String(selectedAccount.value || '').trim(),
498+
username: String(username || '').trim(),
499+
reset: !!reset,
500+
error
501+
})
404502
messagesError.value = error?.message || '加载聊天记录失败'
405503
} finally {
406504
isLoadingMessages.value = false
505+
logMessagePhase('loadMessages:exit', {
506+
username,
507+
reset,
508+
loading: isLoadingMessages.value,
509+
error: messagesError.value
510+
})
407511
}
408512
}
409513

0 commit comments

Comments
 (0)