@@ -635,110 +635,216 @@ function nodeLoader() {
635635 nodeErrorLogCount = 0 ;
636636 } , NODE_ERROR_LOGS_RESET_INTERVAL ) ;
637637
638- window . __TAURI__ . path . resolveResource ( "src-node/index.js" )
639- . then ( async nodeSrcPath => {
640- // Strip Windows UNC prefix (\\?\) that Tauri adds on Windows
641- // Node 24 doesn't handle UNC paths correctly in module resolution
642- if ( Phoenix . platform === "win" && nodeSrcPath . startsWith ( '\\\\?\\' ) ) {
643- nodeSrcPath = nodeSrcPath . slice ( 4 ) ;
638+ async function _tauriNodeSetup ( ) {
639+ let nodeSrcPath = await window . __TAURI__ . path . resolveResource ( "src-node/index.js" ) ;
640+ // Strip Windows UNC prefix (\\?\) that Tauri adds on Windows
641+ // Node 24 doesn't handle UNC paths correctly in module resolution
642+ if ( Phoenix . platform === "win" && nodeSrcPath . startsWith ( '\\\\?\\' ) ) {
643+ nodeSrcPath = nodeSrcPath . slice ( 4 ) ;
644+ }
645+ if ( Phoenix . platform === "linux" ) {
646+ // in linux installed distributions, src-node is present in the same dir as the executable.
647+ const cliArgs = await window . __TAURI__ . invoke ( '_get_commandline_args' ) ;
648+ nodeSrcPath = `${ window . path . dirname ( cliArgs [ 0 ] ) } /src-node/index.js` ;
649+ }
650+ // node is designed such that it is not required at boot time to lower startup time.
651+ // Keep this so to increase boot speed.
652+ const inspectPort = Phoenix . isTestWindow ? getRandomNumber ( 5000 , 50000 ) : 9229 ;
653+ const argsArray = isInspectEnabled ( ) ? [ `--inspect=${ inspectPort } ` , nodeSrcPath ] : [ nodeSrcPath , '' ] ;
654+ command = window . __TAURI__ . shell . Command . sidecar ( 'phnode' , argsArray ) ;
655+ command . on ( 'close' , data => {
656+ window . isNodeTerminated = true ;
657+ window . isNodeReady = false ;
658+ nodeTerminationResolve ( ) ;
659+ console . log ( `PhNode: command finished with code ${ data . code } and signal ${ data . signal } ` ) ;
660+ if ( ! resolved ) {
661+ reject ( "PhNode: closed - Terminated." ) ;
644662 }
645- if ( Phoenix . platform === "linux" && window . __TAURI__ ) {
646- // in linux installed distributions, src-node is present in the same dir as the executable.
647- const cliArgs = await window . __TAURI__ . invoke ( '_get_commandline_args' ) ;
648- nodeSrcPath = `${ window . path . dirname ( cliArgs [ 0 ] ) } /src-node/index.js` ;
663+ } ) ;
664+ command . on ( 'error' , error => {
665+ window . isNodeTerminated = true ;
666+ window . isNodeReady = false ;
667+ nodeTerminationResolve ( ) ;
668+ console . error ( `PhNode: command error: "${ error } "` ) ;
669+ if ( ! resolved ) {
670+ logger . reportError ( error , `PhNode failed to start!` ) ;
671+ reject ( "PhNode: closed - Terminated." ) ;
649672 }
650- // node is designed such that it is not required at boot time to lower startup time.
651- // Keep this so to increase boot speed.
652- const inspectPort = Phoenix . isTestWindow ? getRandomNumber ( 5000 , 50000 ) : 9229 ;
653- const argsArray = isInspectEnabled ( ) ? [ `--inspect=${ inspectPort } ` , nodeSrcPath ] : [ nodeSrcPath , '' ] ;
654- command = window . __TAURI__ . shell . Command . sidecar ( 'phnode' , argsArray ) ;
655- command . on ( 'close' , data => {
656- window . isNodeTerminated = true ;
657- window . isNodeReady = false ;
658- nodeTerminationResolve ( ) ;
659- console . log ( `PhNode: command finished with code ${ data . code } and signal ${ data . signal } ` ) ;
660- if ( ! resolved ) {
661- reject ( "PhNode: closed - Terminated." ) ;
662- }
663- } ) ;
664- command . on ( 'error' , error => {
665- window . isNodeTerminated = true ;
666- window . isNodeReady = false ;
667- nodeTerminationResolve ( ) ;
668- console . error ( `PhNode: command error: "${ error } "` ) ;
669- if ( ! resolved ) {
670- logger . reportError ( error , `PhNode failed to start!` ) ;
671- reject ( "PhNode: closed - Terminated." ) ;
672- }
673- } ) ;
674- command . stdout . on ( 'data' , line => {
675- if ( line ) {
676- if ( line . startsWith ( COMMAND_RESPONSE_PREFIX ) ) {
677- // its a js response object
678- line = line . replace ( COMMAND_RESPONSE_PREFIX , "" ) ;
679- const jsonMsg = JSON . parse ( line ) ;
680- pendingCommands [ jsonMsg . commandID ] . resolve ( jsonMsg . message ) ;
681- delete pendingCommands [ jsonMsg . commandID ] ;
682- } else if ( line . startsWith ( COMMAND_ERROR_PREFIX ) ) {
683- // its a js response object
684- line = line . replace ( COMMAND_ERROR_PREFIX , "" ) ;
685- const err = JSON . parse ( line ) ;
686- logger . reportError ( err , `PhNode ${ err . type } :${ err . code ?err . code :'' } ` ) ;
687- } else {
688- console . log ( `PhNode: ${ line } ` ) ;
689- }
673+ } ) ;
674+ command . stdout . on ( 'data' , line => {
675+ if ( line ) {
676+ if ( line . startsWith ( COMMAND_RESPONSE_PREFIX ) ) {
677+ // its a js response object
678+ line = line . replace ( COMMAND_RESPONSE_PREFIX , "" ) ;
679+ const jsonMsg = JSON . parse ( line ) ;
680+ pendingCommands [ jsonMsg . commandID ] . resolve ( jsonMsg . message ) ;
681+ delete pendingCommands [ jsonMsg . commandID ] ;
682+ } else if ( line . startsWith ( COMMAND_ERROR_PREFIX ) ) {
683+ // its a js response object
684+ line = line . replace ( COMMAND_ERROR_PREFIX , "" ) ;
685+ const err = JSON . parse ( line ) ;
686+ logger . reportError ( err , `PhNode ${ err . type } :${ err . code ?err . code :'' } ` ) ;
687+ } else {
688+ console . log ( `PhNode: ${ line } ` ) ;
690689 }
690+ }
691+ } ) ;
692+ command . stderr . on ( 'data' , line => {
693+ if ( window . debugMode || nodeErrorLogCount < MAX_NODE_ERROR_LOGS_ALLOWED ) {
694+ // in release builds, too many node errors from file system/other sources can
695+ // happen, Eg. user opens a very large project and fs watchers goes bust.
696+ // if that happens, the app may get stuck logging large number of errors to console, so
697+ // we show atmost 10 error lines every 10 seconds in non-debug builds.
698+ console . error ( `PhNode: ${ line } ` ) ;
699+ }
700+ nodeErrorLogCount ++ ;
701+ } ) ;
702+ child = await command . spawn ( ) ;
703+
704+ const execNode = function ( commandCode , commandData ) {
705+ if ( window . isNodeTerminated ) {
706+ return Promise . reject ( "Node is terminated! Cannot execute: " + commandCode ) ;
707+ }
708+ const newCommandID = commandID ++ ;
709+ child . write ( JSON . stringify ( {
710+ commandCode : commandCode , commandID : newCommandID , commandData
711+ } ) + "\n" ) ;
712+ let resolveP , rejectP ;
713+ const promise = new Promise ( ( resolve , reject ) => { resolveP = resolve ; rejectP = reject ; } ) ;
714+ pendingCommands [ newCommandID ] = { resolve : resolveP , reject : rejectP } ;
715+ return promise ;
716+ } ;
717+
718+ window . PhNodeEngine . terminateNode = function ( ) {
719+ if ( ! window . isNodeTerminated ) {
720+ execNode ( NODE_COMMANDS . TERMINATE ) ;
721+ }
722+ return nodeTerminationPromise ;
723+ } ;
724+ window . PhNodeEngine . getInspectPort = function ( ) {
725+ return inspectPort ;
726+ } ;
727+
728+ execNode ( NODE_COMMANDS . GET_ENDPOINTS )
729+ . then ( message => {
730+ fs . setNodeWSEndpoint ( message . phoenixFSURL ) ;
731+ fs . forceUseNodeWSEndpoint ( true ) ;
732+ setNodeWSEndpoint ( message . phoenixNodeURL ) ;
733+ KernalModeTrust . localAutoAuthURL = message . autoAuthURL ;
734+ window . isNodeReady = true ;
735+ resolve ( message ) ;
736+ // node is designed such that it is not required at boot time to lower startup time.
737+ // Keep this so to increase boot speed.
738+ window . PhNodeEngine . _nodeLoadTime = Date . now ( ) - nodeLoadstartTime ;
691739 } ) ;
692- command . stderr . on ( 'data' , line => {
693- if ( window . debugMode || nodeErrorLogCount < MAX_NODE_ERROR_LOGS_ALLOWED ) {
694- // in release builds, too many node errors from file system/other sources can
695- // happen, Eg. user opens a very large project and fs watchers goes bust.
696- // if that happens, the app may get stuck logging large number of errors to console, so
697- // we show atmost 10 error lines every 10 seconds in non-debug builds.
698- console . error ( `PhNode: ${ line } ` ) ;
740+ execNode ( NODE_COMMANDS . SET_DEBUG_MODE , window . debugMode ) ;
741+ }
742+
743+ async function _electronNodeSetup ( ) {
744+ // Get phnode path and src-node path, similar to Tauri's sidecar approach
745+ const phNodePath = await window . electronAPI . getPhNodePath ( ) ;
746+ const nodeSrcPath = `${ await window . electronAPI . getSrcNodePath ( ) } /index.js` ;
747+
748+ const inspectPort = Phoenix . isTestWindow ? getRandomNumber ( 5000 , 50000 ) : 9229 ;
749+ const argsArray = isInspectEnabled ( )
750+ ? [ `--inspect=${ inspectPort } ` , nodeSrcPath ]
751+ : [ nodeSrcPath , '' ] ;
752+
753+ // Spawn the node process
754+ const instanceId = await window . electronAppAPI . spawnProcess ( phNodePath , argsArray ) ;
755+
756+ // Register event handlers - filter by our instanceId since callbacks are global
757+ window . electronAppAPI . onProcessClose ( ( eventInstanceId , data ) => {
758+ if ( eventInstanceId !== instanceId ) {
759+ return ;
760+ }
761+ window . isNodeTerminated = true ;
762+ window . isNodeReady = false ;
763+ nodeTerminationResolve ( ) ;
764+ console . log ( `PhNode: command finished with code ${ data . code } and signal ${ data . signal } ` ) ;
765+ if ( ! resolved ) {
766+ reject ( "PhNode: closed - Terminated." ) ;
767+ }
768+ } ) ;
769+
770+ window . electronAppAPI . onProcessStdout ( ( eventInstanceId , line ) => {
771+ if ( eventInstanceId !== instanceId ) {
772+ return ;
773+ }
774+ if ( line ) {
775+ if ( line . startsWith ( COMMAND_RESPONSE_PREFIX ) ) {
776+ // its a js response object
777+ line = line . replace ( COMMAND_RESPONSE_PREFIX , "" ) ;
778+ const jsonMsg = JSON . parse ( line ) ;
779+ pendingCommands [ jsonMsg . commandID ] . resolve ( jsonMsg . message ) ;
780+ delete pendingCommands [ jsonMsg . commandID ] ;
781+ } else if ( line . startsWith ( COMMAND_ERROR_PREFIX ) ) {
782+ // its a js response object
783+ line = line . replace ( COMMAND_ERROR_PREFIX , "" ) ;
784+ const err = JSON . parse ( line ) ;
785+ logger . reportError ( err , `PhNode ${ err . type } :${ err . code ? err . code : '' } ` ) ;
786+ } else {
787+ console . log ( `PhNode: ${ line } ` ) ;
699788 }
700- nodeErrorLogCount ++ ;
789+ }
790+ } ) ;
791+
792+ window . electronAppAPI . onProcessStderr ( ( eventInstanceId , line ) => {
793+ if ( eventInstanceId !== instanceId ) {
794+ return ;
795+ }
796+ if ( window . debugMode || nodeErrorLogCount < MAX_NODE_ERROR_LOGS_ALLOWED ) {
797+ console . error ( `PhNode: ${ line } ` ) ;
798+ }
799+ nodeErrorLogCount ++ ;
800+ } ) ;
801+
802+ const execNode = function ( commandCode , commandData ) {
803+ if ( window . isNodeTerminated ) {
804+ return Promise . reject ( "Node is terminated! Cannot execute: " + commandCode ) ;
805+ }
806+ const newCommandID = commandID ++ ;
807+ window . electronAppAPI . writeToProcess ( instanceId , JSON . stringify ( {
808+ commandCode : commandCode , commandID : newCommandID , commandData
809+ } ) + "\n" ) ;
810+ let resolveP , rejectP ;
811+ const promise = new Promise ( ( res , rej ) => { resolveP = res ; rejectP = rej ; } ) ;
812+ pendingCommands [ newCommandID ] = { resolve : resolveP , reject : rejectP } ;
813+ return promise ;
814+ } ;
815+
816+ window . PhNodeEngine . terminateNode = function ( ) {
817+ if ( ! window . isNodeTerminated ) {
818+ execNode ( NODE_COMMANDS . TERMINATE ) ;
819+ }
820+ return nodeTerminationPromise ;
821+ } ;
822+ window . PhNodeEngine . getInspectPort = function ( ) {
823+ return inspectPort ;
824+ } ;
825+
826+ execNode ( NODE_COMMANDS . GET_ENDPOINTS )
827+ . then ( message => {
828+ fs . setNodeWSEndpoint ( message . phoenixFSURL ) ;
829+ fs . forceUseNodeWSEndpoint ( true ) ;
830+ setNodeWSEndpoint ( message . phoenixNodeURL ) ;
831+ KernalModeTrust . localAutoAuthURL = message . autoAuthURL ;
832+ window . isNodeReady = true ;
833+ resolve ( message ) ;
834+ window . PhNodeEngine . _nodeLoadTime = Date . now ( ) - nodeLoadstartTime ;
701835 } ) ;
702- child = await command . spawn ( ) ;
836+ execNode ( NODE_COMMANDS . SET_DEBUG_MODE , window . debugMode ) ;
837+ }
703838
704- const execNode = function ( commandCode , commandData ) {
705- if ( window . isNodeTerminated ) {
706- return Promise . reject ( "Node is terminated! Cannot execute: " + commandCode ) ;
707- }
708- const newCommandID = commandID ++ ;
709- child . write ( JSON . stringify ( {
710- commandCode : commandCode , commandID : newCommandID , commandData
711- } ) + "\n" ) ;
712- let resolveP , rejectP ;
713- const promise = new Promise ( ( resolve , reject ) => { resolveP = resolve ; rejectP = reject ; } ) ;
714- pendingCommands [ newCommandID ] = { resolve : resolveP , reject : rejectP } ;
715- return promise ;
716- } ;
717-
718- window . PhNodeEngine . terminateNode = function ( ) {
719- if ( ! window . isNodeTerminated ) {
720- execNode ( NODE_COMMANDS . TERMINATE ) ;
721- }
722- return nodeTerminationPromise ;
723- } ;
724- window . PhNodeEngine . getInspectPort = function ( ) {
725- return inspectPort ;
726- } ;
727-
728- execNode ( NODE_COMMANDS . GET_ENDPOINTS )
729- . then ( message => {
730- fs . setNodeWSEndpoint ( message . phoenixFSURL ) ;
731- fs . forceUseNodeWSEndpoint ( true ) ;
732- setNodeWSEndpoint ( message . phoenixNodeURL ) ;
733- KernalModeTrust . localAutoAuthURL = message . autoAuthURL ;
734- window . isNodeReady = true ;
735- resolve ( message ) ;
736- // node is designed such that it is not required at boot time to lower startup time.
737- // Keep this so to increase boot speed.
738- window . PhNodeEngine . _nodeLoadTime = Date . now ( ) - nodeLoadstartTime ;
739- } ) ;
740- execNode ( NODE_COMMANDS . SET_DEBUG_MODE , window . debugMode ) ;
839+ if ( window . __TAURI__ ) {
840+ _tauriNodeSetup ( ) . catch ( err => {
841+ logger . reportError ( err , "PhNode Tauri setup failed" ) ;
741842 } ) ;
843+ } else if ( window . __ELECTRON__ ) {
844+ _electronNodeSetup ( ) . catch ( err => {
845+ logger . reportError ( err , "PhNode Electron setup failed" ) ;
846+ } ) ;
847+ }
742848 } ) ;
743849}
744850
0 commit comments