diff --git a/src/server/session.ts b/src/server/session.ts index a503509f07be5..a6df5491f3d54 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -940,6 +940,10 @@ namespace ts.server { } return; } + this.writeMessage(msg); + } + + protected writeMessage(msg: protocol.Message) { const msgText = formatMessage(msg, this.logger, this.byteLength, this.host.newLine); perfLogger.logEvent(`Response message size: ${msgText.length}`); this.host.write(msgText); diff --git a/src/tsserver/nodeServer.ts b/src/tsserver/nodeServer.ts index e8e42042d5523..c85943496e386 100644 --- a/src/tsserver/nodeServer.ts +++ b/src/tsserver/nodeServer.ts @@ -233,7 +233,7 @@ namespace ts.server { // Override sys.write because fs.writeSync is not reliable on Node 4 sys.write = (s: string) => writeMessage(sys.bufferFrom!(s, "utf8") as globalThis.Buffer); - // REVIEW: for now this implementation uses polling. + // REVIEW: for now this implementation uses polling. // The advantage of polling is that it works reliably // on all os and with network mounted files. // For 90 referenced files, the average time to detect @@ -759,12 +759,40 @@ namespace ts.server { } } + class IpcIOSession extends IOSession { + + protected writeMessage(msg: protocol.Message): void { + const verboseLogging = logger.hasLevel(LogLevel.verbose); + if (verboseLogging) { + const json = JSON.stringify(msg); + logger.info(`${msg.type}:${indent(json)}`); + } + + process.send!(msg); + } + + protected parseMessage(message: any): protocol.Request { + return message as protocol.Request; + } + + protected toStringMessage(message: any) { + return JSON.stringify(message, undefined, 2); + } + + public listen() { + process.on("message", (e: any) => { + this.onMessage(e); + }); + } + } + const eventPort: number | undefined = parseEventPort(findArgument("--eventPort")); const typingSafeListLocation = findArgument(Arguments.TypingSafeListLocation)!; // TODO: GH#18217 const typesMapLocation = findArgument(Arguments.TypesMapLocation) || combinePaths(getDirectoryPath(sys.getExecutingFilePath()), "typesMap.json"); const npmLocation = findArgument(Arguments.NpmLocation); const validateDefaultNpmLocation = hasArgument(Arguments.ValidateDefaultNpmLocation); const disableAutomaticTypingAcquisition = hasArgument("--disableAutomaticTypingAcquisition"); + const useNodeIpc = hasArgument("--useNodeIpc"); const telemetryEnabled = hasArgument(Arguments.EnableTelemetry); const commandLineTraceDir = findArgument("--traceDirectory"); const traceDir = commandLineTraceDir @@ -774,7 +802,7 @@ namespace ts.server { startTracing("server", traceDir); } - const ioSession = new IOSession(); + const ioSession = useNodeIpc ? new IpcIOSession() : new IOSession(); process.on("uncaughtException", err => { ioSession.logError(err, "unknown"); }); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 116be4316f918..1f270cc92e538 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10470,6 +10470,7 @@ declare namespace ts.server { logError(err: Error, cmd: string): void; private logErrorWorker; send(msg: protocol.Message): void; + protected writeMessage(msg: protocol.Message): void; event(body: T, eventName: string): void; /** @deprecated */ output(info: any, cmdName: string, reqSeq?: number, errorMsg?: string): void;