mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Adds experimental support for running TS Server in a web worker (#39656)
* Adds experimental support for running TS Server in a web worker This change makes it possible to run a syntax old TS server in a webworker. This is will let serverless versions of VS Code web run the TypeScript extension with minimal changes. As the diff on `server.ts` is difficult to parse, here's an overview of the changes: - Introduce the concept of a `Runtime`. Valid values are `Node` and `Web`. - Move calls to `require` into the functions that use these modules - Wrap existing server logic into `startNodeServer` - Introduce web server with `startWebServer`. This uses a `WorkerSession` - Add a custom version of `ts.sys` for web - Have the worker server start when it is passed an array of arguments in a message In order to make the server logic more clear, this change also tries to reduce the reliance on closures and better group function declarations vs the server spawning logic. **Next Steps** I'd like someone from the TS team to help get these changes into a shippable state. This will involve: - Adddress todo comments - Code cleanup - Make sure these changes do not regress node servers - Determine if we should add a new `tsserver.web.js` file instead of having the web worker logic all live in `tsserver.js` * Shim out directoryExists * Add some regions * Remove some inlined note types Use import types instead * Use switch case for runtime * Review and updates * Enable loading std library d.ts files This implements enough of `ServerHost` that we can load the standard d.ts files using synchronous XMLHttpRequests. I also had to patch some code in `editorServices`. I don't know if these changes are correct and need someone on the TS team to review * Update src/tsserver/webServer.ts * Update src/tsserver/webServer.ts Co-authored-by: Sheetal Nandi <shkamat@microsoft.com> * Addressing feedback * Allow passing in explicit executingFilePath This is required for cases where `self.location` does not point to the directory where all the typings are stored * Adding logging support * Do not create auto import provider in partial semantic mode * Handle lib files by doing path mapping instead * TODO * Add log message This replaces the console based logger with a logger that post log messages back to the host. VS Code will write these messages to its output window * Move code around so that exported functions are set on namespace * Log response * Map the paths back to https: // TODO: is this really needed or can vscode take care of this How do we handle when opening lib.d.ts as response to goto def in open files * If files are not open dont schedule open file project ensure * Should also check if there are no external projects before skipping scheduling Fixes failing tests * Revert "Map the paths back to https:" This reverts commit0edf650622. * Revert "TODO" This reverts commit04a4fe7556. * Revert "Should also check if there are no external projects before skipping scheduling" This reverts commit7e4939014a. * Refactoring so we can test the changes out * Feedback Co-authored-by: Sheetal Nandi <shkamat@microsoft.com>
This commit is contained in:
@@ -689,7 +689,7 @@ namespace ts.server {
|
||||
typesMapLocation?: string;
|
||||
}
|
||||
|
||||
export class Session implements EventSender {
|
||||
export class Session<TMessage = string> implements EventSender {
|
||||
private readonly gcTimer: GcTimer;
|
||||
protected projectService: ProjectService;
|
||||
private changeSeq = 0;
|
||||
@@ -2907,7 +2907,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
public onMessage(message: string) {
|
||||
public onMessage(message: TMessage) {
|
||||
this.gcTimer.scheduleCollect();
|
||||
|
||||
this.performanceData = undefined;
|
||||
@@ -2916,18 +2916,18 @@ namespace ts.server {
|
||||
if (this.logger.hasLevel(LogLevel.requestTime)) {
|
||||
start = this.hrtime();
|
||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||
this.logger.info(`request:${indent(message)}`);
|
||||
this.logger.info(`request:${indent(this.toStringMessage(message))}`);
|
||||
}
|
||||
}
|
||||
|
||||
let request: protocol.Request | undefined;
|
||||
let relevantFile: protocol.FileRequestArgs | undefined;
|
||||
try {
|
||||
request = <protocol.Request>JSON.parse(message);
|
||||
request = this.parseMessage(message);
|
||||
relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined;
|
||||
|
||||
tracing.instant(tracing.Phase.Session, "request", { seq: request.seq, command: request.command });
|
||||
perfLogger.logStartCommand("" + request.command, message.substring(0, 100));
|
||||
perfLogger.logStartCommand("" + request.command, this.toStringMessage(message).substring(0, 100));
|
||||
|
||||
tracing.push(tracing.Phase.Session, "executeCommand", { seq: request.seq, command: request.command }, /*separateBeginAndEnd*/ true);
|
||||
const { response, responseRequired } = this.executeCommand(request);
|
||||
@@ -2965,7 +2965,7 @@ namespace ts.server {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logErrorWorker(err, message, relevantFile);
|
||||
this.logErrorWorker(err, this.toStringMessage(message), relevantFile);
|
||||
perfLogger.logStopCommand("" + (request && request.command), "Error: " + err);
|
||||
tracing.instant(tracing.Phase.Session, "commandError", { seq: request?.seq, command: request?.command, message: (<Error>err).message });
|
||||
|
||||
@@ -2978,6 +2978,14 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
protected parseMessage(message: TMessage): protocol.Request {
|
||||
return <protocol.Request>JSON.parse(message as any as string);
|
||||
}
|
||||
|
||||
protected toStringMessage(message: TMessage): string {
|
||||
return message as any as string;
|
||||
}
|
||||
|
||||
private getFormatOptions(file: NormalizedPath): FormatCodeSettings {
|
||||
return this.projectService.getFormatCodeOptions(file);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user