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;
}
}