Website-Suche

typescript - „process.send“ ist sowohl in übergeordneten als auch in untergeordneten Node.js-Prozessen undefiniert (Variante „childProcess.spawn“ verwendet)


Ich möchte den Datenaustausch zwischen meiner Hauptanwendung und der untergeordneten Electron-Anwendung bereitstellen (die GUI könnte von der Konsole aus gestartet werden).

Hauptprozess (aber NICHT Electron „Hauptprozess“)

Der untenstehende Quellcode ist TypeScript.

import Path from "path";
import ChildProcess, { ChildProcess as ChildProcess__type } from "child_process";
import Chalk from "chalk";


export default abstract class ProjectInitializer {

  private static readonly ELECTRON_EXECUTE_FILE_ABSOLUTE_PATH: string = Path.resolve(
      __dirname, "node_modules", ".bin", "electron.cmd"
  );
  private static readonly ELECTRON_MAIN_PROCESS_FILE_ABSOLUTE_PATH: string = Path.resolve(
      __dirname, "ProjectInitializer__ElectronMainProcess.js"
  );


  public static startInitializeProjectGUI(): void {

    console.log(Chalk.cyanBright("GUI is starting ..."));

    const electronApplicationChildProcess: ChildProcess__type = ChildProcess.spawn(
        ProjectInitializer.ELECTRON_EXECUTE_FILE_ABSOLUTE_PATH,
        [
          ProjectInitializer.ELECTRON_MAIN_PROCESS_FILE_ABSOLUTE_PATH,
          "--color", "always"
        ]
    );

    // No TypeScript error but error occurs in compiled JavaScript
    electronApplicationChildProcess.send({ foo: "alpha" });

    electronApplicationChildProcess.on("message", (message: unknown) => {
      console.log(message);
    });
  }
}

Die JavaScript-Fehlermeldung lautet:

TypeError: electronApplicationChildProcess.send is not a function
    at Function.ProjectInitializer.startInitializeProjectGUI (webpack:///./ProjectInitializer/ProjectInitializer.ts?:24:41)
    at Function.HikariAutomation.interpretConsoleCommandAndExecute

Kindprozess (aber in der Electron-Terminologie ist es der „Electron-Hauptprozess“)

import URL from "url";
import Path from "path";

import {
  app as electronApplication,
  App as ElectronApplication,
  BrowserWindow,
} from "electron";
import enableElectronDebug from "electron-debug";


class ProjectInitializerGUI {

  private electronApplication: ElectronApplication;
  private mainWindow: BrowserWindow | null = null;

  private static MAIN_WINDOW_MARKUP__FILE_NAME_WITH_EXTENSION: string = 'ProjectInitializer.html';


  private constructor() {

    this.electronApplication = electronApplication;
    enableElectronDebug();

    this.electronApplication.on('ready', this.onApplicationReadyEventHandler.bind(this));
  }

  public static start(): void {
    new ProjectInitializerGUI();
  }


  private onApplicationReadyEventHandler(): void {

    this.mainWindow = new BrowserWindow({
      width: 1280,
      height: 800,
      useContentSize: true,
      center: true,
      resizable: false,
      fullscreenable: false,
      titleBarStyle: 'hidden',
      webPreferences: {
        nodeIntegration: true
      }
    });

    this.mainWindow.loadURL(URL.format({
      pathname: Path.join(
          __dirname,
          ProjectInitializerGUI.MAIN_WINDOW_MARKUP__FILE_NAME_WITH_EXTENSION
      ),
      protocol: 'file:',
      slashes: true
    }));

    this.mainWindow.setMenu(null);
  }
}


(function executeApplication(): void {

  ProjectInitializerGUI.start();

  process.on("message", (message: unknown) => {
    console.log(message);
  });

  // TypeScript forces to check send method on existence ...
  if (process.send) {
    // but because it's undefined, code in this scope in unreachable
    process.send("Just message");
    process.send({ foo: "alpha", bar: "bravo" })
  }
})();

Hier sind die Typdefinitionen für process.send. Wie Sie sehen, ist es eine optionale Eigenschaft:

interface Process extends EventEmitter {
  // ...
  send?(message: any, sendHandle?: any, options?: { swallowErrors?: boolean}, callback?: (error: Error | null) => void): boolean;
  // ...

Die Definition für child_process ist unterschiedlich. Obwohl mein Fall ein Experiment ist, dessen Ergebnisse die Hypothese widerlegen, dass die send-Methode immer für Kindprozesse existiert, ist in den Typdefinitionen für child_process die send-Eigenschaft erforderlich:

declare module "child_process" {

  // ...

  interface ChildProcess extends events.EventEmitter {
    // ...
    send(message: any, callback?: (error: Error | null) => void): boolean;
  }
}