From 7545b2f6d0738c79c835fab208bf2bc60b32d7ea Mon Sep 17 00:00:00 2001 From: Matt Bierner Date: Wed, 18 Jan 2023 14:32:53 -0800 Subject: [PATCH] Use single TS server output log channel on web (#171679) Previously we were creating a new output channel for each server instance --- .../src/tsServer/serverProcess.browser.ts | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts b/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts index ee47dee2628..41c311bf9fc 100644 --- a/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts +++ b/extensions/typescript-language-features/src/tsServer/serverProcess.browser.ts @@ -13,6 +13,7 @@ import { ServiceConnection } from '@vscode/sync-api-common/browser'; import { Requests, ApiService } from '@vscode/sync-api-service'; import { TypeScriptVersionManager } from './versionManager'; import { FileWatcherManager } from './fileWatchingManager'; + type BrowserWatchEvent = { type: 'watchDirectory' | 'watchFile'; recursive?: boolean; @@ -28,17 +29,22 @@ type BrowserWatchEvent = { }; export class WorkerServerProcess implements TsServerProcess { + @memoize + private static get output(): vscode.OutputChannel { + return vscode.window.createOutputChannel(vscode.l10n.t("TypeScript Server Log")); + } + public static fork( version: TypeScriptVersion, args: readonly string[], - _kind: TsServerProcessKind, + kind: TsServerProcessKind, _configuration: TypeScriptServiceConfiguration, _versionManager: TypeScriptVersionManager, extensionUri: vscode.Uri, ) { const tsServerPath = version.tsServerPath; const worker = new Worker(tsServerPath); - return new WorkerServerProcess(worker, extensionUri, [ + return new WorkerServerProcess(kind, worker, extensionUri, [ ...args, // Explicitly give TS Server its path so it can @@ -47,10 +53,15 @@ export class WorkerServerProcess implements TsServerProcess { ]); } + private static idPool = 0; + + private readonly id = WorkerServerProcess.idPool++; + private readonly _onDataHandlers = new Set<(data: Proto.Response) => void>(); private readonly _onErrorHandlers = new Set<(err: Error) => void>(); private readonly _onExitHandlers = new Set<(code: number | null, signal: string | null) => void>(); private readonly watches = new FileWatcherManager(); + /** For communicating with TS server synchronously */ private readonly tsserver: MessagePort; /** For communicating watches asynchronously */ @@ -59,6 +70,7 @@ export class WorkerServerProcess implements TsServerProcess { private readonly syncFs: MessagePort; public constructor( + private readonly kind: TsServerProcessKind, /** For logging and initial setup */ private readonly mainChannel: Worker, extensionUri: vscode.Uri, @@ -70,6 +82,7 @@ export class WorkerServerProcess implements TsServerProcess { this.tsserver = tsserverChannel.port2; this.watcher = watcherChannel.port2; this.syncFs = syncChannel.port2; + this.tsserver.onmessage = (event) => { if (event.data.type === 'log') { console.error(`unexpected log message on tsserver channel: ${JSON.stringify(event)}`); @@ -79,6 +92,7 @@ export class WorkerServerProcess implements TsServerProcess { handler(event.data); } }; + this.watcher.onmessage = (event: MessageEvent) => { switch (event.data.type) { case 'dispose': { @@ -98,14 +112,16 @@ export class WorkerServerProcess implements TsServerProcess { console.error(`unexpected message on watcher channel: ${JSON.stringify(event)}`); } }; + mainChannel.onmessage = (msg: any) => { // for logging only if (msg.data.type === 'log') { - this.output.append(msg.data.body); + this.appendOutput(msg.data.body); return; } console.error(`unexpected message on main channel: ${JSON.stringify(msg)}`); }; + mainChannel.onerror = (err: ErrorEvent) => { console.error('error! ' + JSON.stringify(err)); for (const handler of this._onErrorHandlers) { @@ -113,20 +129,17 @@ export class WorkerServerProcess implements TsServerProcess { handler(err.error); } }; - this.output.append(`creating new MessageChannel and posting its port2 + args: ${args.join(' ')}\n`); + + this.appendOutput(`creating new MessageChannel and posting its port2 + args: ${args.join(' ')}\n`); mainChannel.postMessage( { args, extensionUri }, [syncChannel.port1, tsserverChannel.port1, watcherChannel.port1] ); + const connection = new ServiceConnection(syncChannel.port2); new ApiService('vscode-wasm-typescript', connection); connection.signalReady(); - this.output.append('done constructing WorkerServerProcess\n'); - } - - @memoize - private get output(): vscode.OutputChannel { - return vscode.window.createOutputChannel(vscode.l10n.t("TypeScript Server Log")); + this.appendOutput('done constructing WorkerServerProcess\n'); } write(serverRequest: Proto.Request): void { @@ -152,5 +165,9 @@ export class WorkerServerProcess implements TsServerProcess { this.watcher.close(); this.syncFs.close(); } + + private appendOutput(msg: string) { + WorkerServerProcess.output.append(`(${this.id} - ${this.kind}) ${msg}`); + } }