1- const { app, BrowserWindow, Menu, ipcMain, globalShortcut } = require ( "electron" ) ;
1+ const {
2+ app,
3+ BrowserWindow,
4+ Menu,
5+ ipcMain,
6+ globalShortcut,
7+ dialog,
8+ shell,
9+ } = require ( "electron" ) ;
210const { spawn } = require ( "child_process" ) ;
311const fs = require ( "fs" ) ;
412const http = require ( "http" ) ;
@@ -9,6 +17,74 @@ const BACKEND_PORT = Number(process.env.WECHAT_TOOL_PORT || "8000");
917const BACKEND_HEALTH_URL = `http://${ BACKEND_HOST } :${ BACKEND_PORT } /api/health` ;
1018
1119let backendProc = null ;
20+ let backendStdioStream = null ;
21+
22+ function nowIso ( ) {
23+ return new Date ( ) . toISOString ( ) ;
24+ }
25+
26+ function getUserDataDir ( ) {
27+ try {
28+ return app . getPath ( "userData" ) ;
29+ } catch {
30+ return null ;
31+ }
32+ }
33+
34+ function getMainLogPath ( ) {
35+ const dir = getUserDataDir ( ) ;
36+ if ( ! dir ) return null ;
37+ return path . join ( dir , "desktop-main.log" ) ;
38+ }
39+
40+ function logMain ( line ) {
41+ const p = getMainLogPath ( ) ;
42+ if ( ! p ) return ;
43+ try {
44+ fs . mkdirSync ( path . dirname ( p ) , { recursive : true } ) ;
45+ fs . appendFileSync ( p , `[${ nowIso ( ) } ] ${ line } \n` , { encoding : "utf8" } ) ;
46+ } catch { }
47+ }
48+
49+ function getBackendStdioLogPath ( dataDir ) {
50+ return path . join ( dataDir , "backend-stdio.log" ) ;
51+ }
52+
53+ function attachBackendStdio ( proc , logPath ) {
54+ // In packaged builds, stdout/stderr are often the only place we can see early crash
55+ // reasons (missing DLLs, import errors) before the Python logger initializes.
56+ try {
57+ fs . mkdirSync ( path . dirname ( logPath ) , { recursive : true } ) ;
58+ } catch { }
59+
60+ try {
61+ backendStdioStream = fs . createWriteStream ( logPath , { flags : "a" } ) ;
62+ backendStdioStream . write ( `[${ nowIso ( ) } ] [main] backend stdio -> ${ logPath } \n` ) ;
63+ } catch {
64+ backendStdioStream = null ;
65+ return ;
66+ }
67+
68+ const write = ( prefix , chunk ) => {
69+ if ( ! backendStdioStream ) return ;
70+ try {
71+ const text = Buffer . isBuffer ( chunk ) ? chunk . toString ( "utf8" ) : String ( chunk ) ;
72+ backendStdioStream . write ( `[${ nowIso ( ) } ] ${ prefix } ${ text } ` ) ;
73+ if ( ! text . endsWith ( "\n" ) ) backendStdioStream . write ( "\n" ) ;
74+ } catch { }
75+ } ;
76+
77+ if ( proc . stdout ) proc . stdout . on ( "data" , ( d ) => write ( "[backend:stdout]" , d ) ) ;
78+ if ( proc . stderr ) proc . stderr . on ( "data" , ( d ) => write ( "[backend:stderr]" , d ) ) ;
79+ proc . on ( "error" , ( err ) => write ( "[backend:error]" , err ?. stack || String ( err ) ) ) ;
80+ proc . on ( "close" , ( code , signal ) => {
81+ write ( "[backend:close]" , `code=${ code } signal=${ signal } ` ) ;
82+ try {
83+ backendStdioStream ?. end ( ) ;
84+ } catch { }
85+ backendStdioStream = null ;
86+ } ) ;
87+ }
1288
1389function repoRoot ( ) {
1490 // desktop/src -> desktop -> repo root
@@ -27,6 +103,8 @@ function startBackend() {
27103 ...process . env ,
28104 WECHAT_TOOL_HOST : BACKEND_HOST ,
29105 WECHAT_TOOL_PORT : String ( BACKEND_PORT ) ,
106+ // Make sure Python prints UTF-8 to stdout/stderr.
107+ PYTHONIOENCODING : process . env . PYTHONIOENCODING || "utf-8" ,
30108 } ;
31109
32110 // In packaged mode we expect to provide the generated Nuxt output dir via env.
@@ -51,9 +129,10 @@ function startBackend() {
51129 backendProc = spawn ( backendExe , [ ] , {
52130 cwd : env . WECHAT_TOOL_DATA_DIR ,
53131 env,
54- stdio : "ignore" ,
132+ stdio : [ "ignore" , "pipe" , "pipe" ] ,
55133 windowsHide : true ,
56134 } ) ;
135+ attachBackendStdio ( backendProc , getBackendStdioLogPath ( env . WECHAT_TOOL_DATA_DIR ) ) ;
57136 } else {
58137 backendProc = spawn ( "uv" , [ "run" , "main.py" ] , {
59138 cwd : repoRoot ( ) ,
@@ -67,6 +146,7 @@ function startBackend() {
67146 backendProc = null ;
68147 // eslint-disable-next-line no-console
69148 console . log ( `[backend] exited code=${ code } signal=${ signal } ` ) ;
149+ logMain ( `[backend] exited code=${ code } signal=${ signal } ` ) ;
70150 } ) ;
71151
72152 return backendProc ;
@@ -124,12 +204,12 @@ async function waitForBackend({ timeoutMs }) {
124204
125205function debugEnabled ( ) {
126206 // Enable debug helpers in dev by default; in packaged builds require explicit opt-in.
127- return ! app . isPackaged || process . env . WECHAT_DESKTOP_DEBUG === "1" ;
207+ if ( ! app . isPackaged ) return true ;
208+ if ( process . env . WECHAT_DESKTOP_DEBUG === "1" ) return true ;
209+ return process . argv . includes ( "--debug" ) || process . argv . includes ( "--devtools" ) ;
128210}
129211
130212function registerDebugShortcuts ( ) {
131- if ( ! debugEnabled ( ) ) return ;
132-
133213 const toggleDevTools = ( ) => {
134214 const win = BrowserWindow . getFocusedWindow ( ) || BrowserWindow . getAllWindows ( ) [ 0 ] ;
135215 if ( ! win ) return ;
@@ -186,7 +266,9 @@ function createMainWindow() {
186266 preload : path . join ( __dirname , "preload.cjs" ) ,
187267 contextIsolation : true ,
188268 nodeIntegration : false ,
189- devTools : debugEnabled ( ) ,
269+ // Allow DevTools to be opened in packaged builds (F12 / Ctrl+Shift+I).
270+ // We still only auto-open it when debugEnabled() returns true.
271+ devTools : true ,
190272 } ,
191273 } ) ;
192274
@@ -245,6 +327,8 @@ async function main() {
245327 registerWindowIpc ( ) ;
246328 registerDebugShortcuts ( ) ;
247329
330+ logMain ( `[main] app.isPackaged=${ app . isPackaged } argv=${ JSON . stringify ( process . argv ) } ` ) ;
331+
248332 startBackend ( ) ;
249333 await waitForBackend ( { timeoutMs : 30_000 } ) ;
250334
@@ -282,6 +366,17 @@ app.on("before-quit", () => {
282366main ( ) . catch ( ( err ) => {
283367 // eslint-disable-next-line no-console
284368 console . error ( err ) ;
369+ logMain ( `[main] fatal: ${ err ?. stack || String ( err ) } ` ) ;
285370 stopBackend ( ) ;
371+ try {
372+ const dir = getUserDataDir ( ) ;
373+ if ( dir ) {
374+ dialog . showErrorBox (
375+ "WeChatDataAnalysis 启动失败" ,
376+ `启动失败:${ err ?. message || err } \n\n请查看日志目录:\n${ dir } \n\n文件:desktop-main.log / backend-stdio.log / output\\\\logs\\\\...`
377+ ) ;
378+ shell . openPath ( dir ) ;
379+ }
380+ } catch { }
286381 app . quit ( ) ;
287382} ) ;
0 commit comments