@@ -56,13 +56,26 @@ export class ProcessManager {
5656 /** 杀掉占用指定端口的进程 */
5757 private killPortProcess ( port : number ) : void {
5858 try {
59- const result = execSync ( `lsof -ti tcp:${ port } ` , { encoding : 'utf-8' } ) . trim ( ) ;
59+ let cmd : string ;
60+ if ( process . platform === 'win32' ) {
61+ cmd = `powershell -Command "Get-NetTCPConnection -LocalPort ${ port } -ErrorAction SilentlyContinue | ForEach-Object { $_.OwningProcess }"` ;
62+ } else {
63+ cmd = `lsof -ti tcp:${ port } ` ;
64+ }
65+ const result = execSync ( cmd , { encoding : 'utf-8' } ) . trim ( ) ;
6066 if ( result ) {
6167 for ( const pid of result . split ( '\n' ) ) {
62- try {
63- process . kill ( parseInt ( pid ) , 'SIGKILL' ) ;
64- this . logger . info ( `Killed stale process ${ pid } on port ${ port } ` ) ;
65- } catch { /* already dead */ }
68+ const p = parseInt ( pid . trim ( ) ) ;
69+ if ( p > 0 ) {
70+ try {
71+ if ( process . platform === 'win32' ) {
72+ execSync ( `taskkill /PID ${ p } /F` , { encoding : 'utf-8' } ) ;
73+ } else {
74+ process . kill ( p , 'SIGKILL' ) ;
75+ }
76+ this . logger . info ( `Killed stale process ${ p } on port ${ port } ` ) ;
77+ } catch { /* already dead */ }
78+ }
6679 }
6780 }
6881 } catch { /* no process on port */ }
@@ -172,30 +185,55 @@ export class ProcessManager {
172185 } ;
173186
174187 if ( usePacked ) {
175- // utilityProcess 不会在 Dock 多出图标
176- this . logger . info ( `Starting frontend (utilityProcess): ${ serverJs } ` ) ;
177-
178- const up = utilityProcess . fork ( serverJs , [ ] , {
179- cwd : nextDir ,
180- env,
181- stdio : 'pipe' ,
182- } ) ;
183-
184- up . stdout ?. on ( 'data' , ( data : Buffer ) => {
185- this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
186- } ) ;
187-
188- up . stderr ?. on ( 'data' , ( data : Buffer ) => {
189- this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
190- } ) ;
191-
192- up . on ( 'exit' , ( code ) => {
193- if ( code !== 0 ) {
194- this . logger . warn ( `Frontend exited with code ${ code } ` ) ;
195- }
196- } ) ;
197-
198- this . frontendProcess = up as unknown as ChildProcess ;
188+ // macOS: utilityProcess 不在 Dock 显示图标; Windows: spawn 更稳定
189+ if ( process . platform === 'win32' ) {
190+ this . logger . info ( `Starting frontend (spawn): node ${ serverJs } ` ) ;
191+ const procEnv = {
192+ ...process . env ,
193+ ...env ,
194+ NODE_PATH : path . join ( nextDir , 'node_modules' ) ,
195+ } ;
196+ this . frontendProcess = spawn ( 'node' , [ serverJs ] , {
197+ cwd : nextDir ,
198+ env : procEnv ,
199+ stdio : [ 'ignore' , 'pipe' , 'pipe' ] ,
200+ detached : false ,
201+ shell : false ,
202+ } ) ;
203+ this . frontendProcess . stdout ?. on ( 'data' , ( data ) => {
204+ this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
205+ } ) ;
206+ this . frontendProcess . stderr ?. on ( 'data' , ( data ) => {
207+ this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
208+ } ) ;
209+ this . frontendProcess . on ( 'error' , ( error ) => {
210+ this . logger . error ( 'Frontend process error' , error ) ;
211+ } ) ;
212+ this . frontendProcess . on ( 'exit' , ( code ) => {
213+ if ( code !== 0 ) {
214+ this . logger . warn ( `Frontend exited with code ${ code } ` ) ;
215+ }
216+ } ) ;
217+ } else {
218+ this . logger . info ( `Starting frontend (utilityProcess): ${ serverJs } ` ) ;
219+ const up = utilityProcess . fork ( serverJs , [ ] , {
220+ cwd : nextDir ,
221+ env,
222+ stdio : 'pipe' ,
223+ } ) ;
224+ up . stdout ?. on ( 'data' , ( data : Buffer ) => {
225+ this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
226+ } ) ;
227+ up . stderr ?. on ( 'data' , ( data : Buffer ) => {
228+ this . logger . debug ( `[Frontend] ${ data . toString ( ) . trim ( ) } ` ) ;
229+ } ) ;
230+ up . on ( 'exit' , ( code ) => {
231+ if ( code !== 0 ) {
232+ this . logger . warn ( `Frontend exited with code ${ code } ` ) ;
233+ }
234+ } ) ;
235+ this . frontendProcess = up as unknown as ChildProcess ;
236+ }
199237 } else {
200238 // 开发模式:用 next start
201239 this . logger . info ( 'Starting frontend (dev mode): next start' ) ;
0 commit comments