Skip to content

Adds experimental support for running TS Server in a web worker #39656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e50aedc
Adds experimental support for running TS Server in a web worker
mjbvz Jul 18, 2020
30cb1a6
Shim out directoryExists
mjbvz Jul 23, 2020
fb900a0
Add some regions
mjbvz Aug 31, 2020
4ce8d4a
Remove some inlined note types
mjbvz Aug 31, 2020
94faf66
Use switch case for runtime
mjbvz Aug 31, 2020
f6c0749
Merge branch 'master' into web-worker-server
sheetalkamat Sep 22, 2020
f3178b6
Review and updates
sheetalkamat Sep 23, 2020
6202c51
Enable loading std library d.ts files
mjbvz Sep 25, 2020
b6e8137
Update src/tsserver/webServer.ts
sheetalkamat Sep 28, 2020
dd331e2
Update src/tsserver/webServer.ts
mjbvz Sep 29, 2020
2d4c726
Addressing feedback
mjbvz Sep 29, 2020
69a6523
Allow passing in explicit executingFilePath
mjbvz Sep 29, 2020
5185f6e
Adding logging support
mjbvz Sep 30, 2020
1db3ebc
Do not create auto import provider in partial semantic mode
sheetalkamat Oct 1, 2020
9a1eace
Handle lib files by doing path mapping instead
sheetalkamat Oct 1, 2020
c92d22d
Merge branch 'master' into web-worker-server
sheetalkamat Oct 2, 2020
14498b8
Merge branch 'master' into web-worker-server
sheetalkamat Oct 27, 2020
04a4fe7
TODO
sheetalkamat Oct 27, 2020
b959f3e
Add log message
mjbvz Nov 12, 2020
2359c83
Move code around so that exported functions are set on namespace
sheetalkamat Nov 13, 2020
f29b2e7
Log response
sheetalkamat Nov 13, 2020
0edf650
Map the paths back to https:
sheetalkamat Nov 14, 2020
0820519
If files are not open dont schedule open file project ensure
sheetalkamat Nov 14, 2020
7e49390
Should also check if there are no external projects before skipping s…
sheetalkamat Nov 14, 2020
16ff1ce
Revert "Map the paths back to https:"
sheetalkamat Nov 18, 2020
9952bab
Revert "TODO"
sheetalkamat Nov 18, 2020
2bf35c9
Revert "Should also check if there are no external projects before sk…
sheetalkamat Nov 18, 2020
3c94c98
Merge branch 'master' into web-worker-server
sheetalkamat Nov 21, 2020
542a8b0
Refactoring so we can test the changes out
sheetalkamat Nov 21, 2020
245e49d
Feedback
sheetalkamat Dec 2, 2020
9704738
Merge branch 'master' into web-worker-server
sheetalkamat Dec 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ namespace ts {
/**
* Computing hash to for signature verification
*/
const computeHash = host.createHash || generateDjb2Hash;
const computeHash = maybeBind(host, host.createHash);
let state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState);
let backupState: BuilderProgramState | undefined;
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state, getCanonicalFileName);
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/builderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ namespace ts {
/**
* Compute the hash to store the shape of the file
*/
export type ComputeHash = (data: string) => string;
export type ComputeHash = ((data: string) => string) | undefined;

/**
* Exported modules to from declaration emit being computed.
Expand Down Expand Up @@ -337,7 +337,7 @@ namespace ts {
emitOutput.outputFiles.length > 0 ? emitOutput.outputFiles[0] : undefined;
if (firstDts) {
Debug.assert(fileExtensionIs(firstDts.name, Extension.Dts), "File extension for signature expected to be dts", () => `Found: ${getAnyExtensionFromPath(firstDts.name)} for ${firstDts.name}:: All output files: ${JSON.stringify(emitOutput.outputFiles.map(f => f.name))}`);
latestSignature = computeHash(firstDts.text);
latestSignature = (computeHash || generateDjb2Hash)(firstDts.text);
if (exportedModulesMapCache && latestSignature !== prevSignature) {
updateExportedModules(sourceFile, emitOutput.exportedModulesFromDeclarationEmit, exportedModulesMapCache);
}
Expand Down Expand Up @@ -521,7 +521,7 @@ namespace ts {
/**
* When program emits modular code, gets the files affected by the sourceFile whose shape has changed
*/
function getFilesAffectedByUpdatedShapeWhenModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile, cacheToUpdateSignature: ESMap<Path, string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash | undefined, exportedModulesMapCache: ComputingExportedModulesMap | undefined) {
function getFilesAffectedByUpdatedShapeWhenModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile, cacheToUpdateSignature: ESMap<Path, string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, exportedModulesMapCache: ComputingExportedModulesMap | undefined) {
if (isFileAffectingGlobalScope(sourceFileWithUpdatedShape)) {
return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape);
}
Expand All @@ -544,7 +544,7 @@ namespace ts {
if (!seenFileNamesMap.has(currentPath)) {
const currentSourceFile = programOfThisState.getSourceFileByPath(currentPath)!;
seenFileNamesMap.set(currentPath, currentSourceFile);
if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cacheToUpdateSignature, cancellationToken, computeHash!, exportedModulesMapCache)) { // TODO: GH#18217
if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cacheToUpdateSignature, cancellationToken, computeHash, exportedModulesMapCache)) { // TODO: GH#18217
queue.push(...getReferencedByPaths(state, currentSourceFile.resolvedPath));
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace ts {
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
const existingDirectories = new Map<string, boolean>();
const getCanonicalFileName = createGetCanonicalFileName(system.useCaseSensitiveFileNames);
const computeHash = maybeBind(system, system.createHash) || generateDjb2Hash;
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
let text: string | undefined;
try {
Expand Down Expand Up @@ -128,7 +129,7 @@ namespace ts {

let outputFingerprints: ESMap<string, OutputFingerprint>;
function writeFileWorker(fileName: string, data: string, writeByteOrderMark: boolean) {
if (!isWatchSet(options) || !system.createHash || !system.getModifiedTime) {
if (!isWatchSet(options) || !system.getModifiedTime) {
system.writeFile(fileName, data, writeByteOrderMark);
return;
}
Expand All @@ -137,7 +138,7 @@ namespace ts {
outputFingerprints = new Map<string, OutputFingerprint>();
}

const hash = system.createHash(data);
const hash = computeHash(data);
const mtimeBefore = system.getModifiedTime(fileName);

if (mtimeBefore) {
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,11 @@ namespace ts {

export function setGetSourceFileAsHashVersioned(compilerHost: CompilerHost, host: { createHash?(data: string): string; }) {
const originalGetSourceFile = compilerHost.getSourceFile;
const computeHash = host.createHash || generateDjb2Hash;
const computeHash = maybeBind(host, host.createHash) || generateDjb2Hash;
compilerHost.getSourceFile = (...args) => {
const result = originalGetSourceFile.call(compilerHost, ...args);
if (result) {
result.version = computeHash.call(host, result.text);
result.version = computeHash(result.text);
}
return result;
};
Expand Down
5 changes: 2 additions & 3 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,6 @@ namespace ts.server {
this.syntaxOnly = false;
}

Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService");
if (this.host.realpath) {
this.realpathToScriptInfos = createMultiMap();
}
Expand Down Expand Up @@ -2490,7 +2489,7 @@ namespace ts.server {
}

private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName: NormalizedPath, currentDirectory: string, scriptKind: ScriptKind | undefined, hasMixedContent: boolean | undefined, hostToQueryFileExistsOn: DirectoryStructureHost | undefined) {
if (isRootedDiskPath(fileName) || isDynamicFileName(fileName)) {
if (isRootedDiskPath(fileName) || isDynamicFileName(fileName) || isUrl(fileName)) {
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ false, /*fileContent*/ undefined, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
}

Expand Down Expand Up @@ -2520,7 +2519,7 @@ namespace ts.server {
let info = this.getScriptInfoForPath(path);
if (!info) {
const isDynamic = isDynamicFileName(fileName);
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
Debug.assert(isRootedDiskPath(fileName) || isUrl(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info or in context of host currentDirectory`);
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory || this.useInferredProjectPerProjectRoot, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always be opened with service's current directory or service should support inferred project per projectRootPath.`);
// If the file is not opened by client and the file doesnot exist on the disk, return
Expand Down
7 changes: 5 additions & 2 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ namespace ts.server {
}
updateProjectIfDirty(this);
this.builderState = BuilderState.create(this.program!, this.projectService.toCanonicalFileName, this.builderState);
return mapDefined(BuilderState.getFilesAffectedBy(this.builderState, this.program!, scriptInfo.path, this.cancellationToken, data => this.projectService.host.createHash!(data)), // TODO: GH#18217
return mapDefined(BuilderState.getFilesAffectedBy(this.builderState, this.program!, scriptInfo.path, this.cancellationToken, maybeBind(this.projectService.host, this.projectService.host.createHash)),
sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName : undefined);
}

Expand All @@ -654,7 +654,10 @@ namespace ts.server {
const dtsFiles = outputFiles.filter(f => fileExtensionIs(f.name, Extension.Dts));
if (dtsFiles.length === 1) {
const sourceFile = this.program!.getSourceFile(scriptInfo.fileName)!;
BuilderState.updateSignatureOfFile(this.builderState, this.projectService.host.createHash!(dtsFiles[0].text), sourceFile.resolvedPath);
const signature = this.projectService.host.createHash ?
this.projectService.host.createHash(dtsFiles[0].text) :
generateDjb2Hash(dtsFiles[0].text);
BuilderState.updateSignatureOfFile(this.builderState, signature, sourceFile.resolvedPath);
}
}
}
Expand Down
20 changes: 14 additions & 6 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ namespace ts.server {
typesMapLocation?: string;
}

export class Session implements EventSender {
export class Session<MessageType = string> implements EventSender {
private readonly gcTimer: GcTimer;
protected projectService: ProjectService;
private changeSeq = 0;
Expand Down Expand Up @@ -2896,7 +2896,7 @@ namespace ts.server {
}
}

public onMessage(message: string) {
public onMessage(message: MessageType) {
this.gcTimer.scheduleCollect();

this.performanceData = undefined;
Expand All @@ -2905,17 +2905,17 @@ 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;

perfLogger.logStartCommand("" + request.command, message.substring(0, 100));
perfLogger.logStartCommand("" + request.command, this.toStringMessage(message).substring(0, 100));
const { response, responseRequired } = this.executeCommand(request);

if (this.logger.hasLevel(LogLevel.requestTime)) {
Expand Down Expand Up @@ -2945,7 +2945,7 @@ namespace ts.server {
return;
}

this.logErrorWorker(err, message, relevantFile);
this.logErrorWorker(err, this.toStringMessage(message), relevantFile);
perfLogger.logStopCommand("" + (request && request.command), "Error: " + err);

this.doOutput(
Expand All @@ -2957,6 +2957,14 @@ namespace ts.server {
}
}

protected parseMessage(message: MessageType): protocol.Request {
return <protocol.Request>JSON.parse(message as any as string);
}

protected toStringMessage(message: MessageType): string {
return message as any as string;
}

private getFormatOptions(file: NormalizedPath): FormatCodeSettings {
return this.projectService.getFormatCodeOptions(file);
}
Expand Down
Loading