chore(frontend): add diagnostics before app split

- main.js: global error handlers (error + unhandledrejection), try/catch around App mount with inline fallback UI
- bindings_logging.go: FrontendLog() and LogStartupStep() backend bindings for persistent application logging
- App.js: FrontendLog() and LogStartupStep() Wails JS bindings
- docs/frontend-architecture.md: component architecture, state ownership rules, communication patterns, logging guide, troubleshooting

All existing code untouched. This is a pure additive step that enables
blank-window debugging before any App.svelte extraction begins.
This commit is contained in:
2026-06-16 02:22:44 +08:00
parent bfe57ac0ac
commit df21340402
6 changed files with 335 additions and 5 deletions
+45 -2
View File
@@ -1,5 +1,48 @@
import App from './App.svelte'
new App({
target: document.getElementById('app')
// ===== Global frontend error diagnostics =====
// These catch runtime errors that would otherwise cause a silent blank window.
window.addEventListener('error', (event) => {
const msg = event.error ? String(event.error) : event.message
const stack = event.error && event.error.stack ? event.error.stack : ''
console.error('[Frontend Error]', msg, stack)
try {
if (window['go'] && window['go']['main'] && window['go']['main']['App'] && typeof window['go']['main']['App']['FrontendLog'] === 'function') {
window['go']['main']['App']['FrontendLog']('error', msg, stack)
}
} catch (e) {
// Backend not ready — ignore
}
})
window.addEventListener('unhandledrejection', (event) => {
const reason = event.reason
const msg = reason instanceof Error ? String(reason) : JSON.stringify(reason)
const stack = reason instanceof Error && reason.stack ? reason.stack : ''
console.error('[Unhandled Promise Rejection]', msg, stack)
try {
if (window['go'] && window['go']['main'] && window['go']['main']['App'] && typeof window['go']['main']['App']['FrontendLog'] === 'function') {
window['go']['main']['App']['FrontendLog']('error', 'Unhandled rejection: ' + msg, stack)
}
} catch (e) {
// Backend not ready — ignore
}
})
// Mount App with error fallback
try {
new App({
target: document.getElementById('app')
})
} catch (e) {
console.error('[Fatal] App mount failed:', e)
const el = document.getElementById('app')
if (el) {
el.innerHTML = '<div style="padding:24px;color:#ff6b6b;font-family:monospace;white-space:pre-wrap">'
+ '<h2>Frontend Runtime Error</h2>'
+ '<p>' + String(e) + '</p>'
+ (e.stack ? '<pre>' + e.stack + '</pre>' : '')
+ '</div>'
}
}
+21 -1
View File
@@ -243,5 +243,25 @@ export function CountActivityByNode(arg1) {
}
export function CreateEmptyFile(arg1, arg2) {
return window['go']['main']['App']['CreateEmptyFile'](arg1, arg2);
return window['go']['main']['App']['CreateEmptyFile'](arg1, arg2)
}
// ===== Logging & Diagnostics =====
export function FrontendLog(level, message, stack) {
try {
if (window['go'] && window['go']['main'] && window['go']['main']['App']) {
return window['go']['main']['App']['FrontendLog'](level, message, stack || '')
}
} catch (e) {}
return Promise.resolve()
}
export function LogStartupStep(step, success, detail) {
try {
if (window['go'] && window['go']['main'] && window['go']['main']['App']) {
return window['go']['main']['App']['LogStartupStep'](step, success, detail || '')
}
} catch (e) {}
return Promise.resolve()
}