Skip to content

Commit c8561e5

Browse files
committed
A TSServer implementation that just uses the files list to avoid looking all over the file system.
Improves performance when running on a network file system.
1 parent 1a579d9 commit c8561e5

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

src/server/g3ServerHostProxy.ts

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/// <reference path="./types.ts"/>
2+
3+
namespace ts.server {
4+
function isGenerated(path: string) {
5+
const GEN_EXT = ['ngsummary', 'ngstyle', 'ngfactory'];
6+
const TS_EXT = ['ts', 'tsx', 'd.ts'];
7+
8+
for (const gen of GEN_EXT) {
9+
for (const ext of TS_EXT) {
10+
if (fileExtensionIs(path, gen + '.' + ext)) {
11+
return true;
12+
}
13+
}
14+
}
15+
return false;
16+
}
17+
18+
export function getG3ServerHostProxy(
19+
tsconfigPath: string,
20+
host: ServerHost,
21+
logger: Logger): ServerHost {
22+
23+
let proxyHost:ServerHost = (<any>Object).assign({}, host);
24+
25+
const {config, error} = readConfigFile(tsconfigPath, proxyHost.readFile);
26+
if (!error) {
27+
const projectDir = getDirectoryPath(tsconfigPath);
28+
29+
// Get the files list from the tsconfig.
30+
let {options, errors, fileNames} =
31+
parseJsonConfigFileContent(config, proxyHost, projectDir);
32+
if (!errors || errors.length === 0) {
33+
// Get the list of files into a map.
34+
let fileMap: {[k: string]: boolean} = {};
35+
36+
// Just put the directory of the files in the known directories list.
37+
// We don't rely on the behavior of walking up the directories to find
38+
// the node_modules. (This part may not work for opensource)
39+
let directoryMap: {[k: string]: boolean} = {};
40+
let rootDirs = options.rootDirs;
41+
42+
// Add all the rootDirs to the known directories list.
43+
options.rootDirs.forEach(d => {
44+
logger.info('Adding rootdir: ' + d);
45+
directoryMap[d] = true;
46+
});
47+
48+
// Add the tsconfig.json as a valid project file.
49+
fileMap[tsconfigPath] = true;
50+
51+
// For each file add to the filesMap and add their directory
52+
// (and few directories above them) to the directoryMap.
53+
fileNames.forEach(f => {
54+
f = proxyHost.resolvePath(f);
55+
logger.info('Adding file: ' + f);
56+
fileMap[f] = true;
57+
// TODO(viks): How deep should we go? Is 2 enough?
58+
for (let i = 0; i < 2; i++) {
59+
f = getDirectoryPath(f);
60+
if (f) {
61+
logger.info('Adding dir: ' + getDirectoryPath(f));
62+
directoryMap[f] = true;
63+
} else {
64+
break;
65+
}
66+
}
67+
});
68+
69+
// Override the fileExists in the ServerHost to reply using the fileMap
70+
// instead of hitting the (network) file system.
71+
proxyHost.fileExists = (path: string) => {
72+
path = proxyHost.resolvePath(path);
73+
if (path in fileMap) {
74+
// File found in map!
75+
logger.info('Found: ' + path);
76+
return true;
77+
} else {
78+
// Only ever allow looking in the filesystem for files inside
79+
// the project dir. Allows for discovery of new source files
80+
// in the project without having to rebuild tsconfig.
81+
// Skip generated files since the tsconfig would have to generated anyways
82+
// while regenerating these.
83+
if (!isGenerated(path)) {
84+
for (const rootDir of rootDirs) {
85+
if (path.indexOf(rootDir) === 0) {
86+
logger.info('Search: ' + path);
87+
return host.fileExists(path);
88+
}
89+
}
90+
}
91+
}
92+
// File not in map. Just return false without hitting file system.
93+
logger.info('Did not find: ' + path);
94+
return false;
95+
}
96+
97+
// Override the directoryExists in the ServerHost to reply using the
98+
// directoryMap without hitting the file system.
99+
proxyHost.directoryExists = (path: string) => {
100+
path = proxyHost.resolvePath(path);
101+
if (path in directoryMap) {
102+
logger.info('Dir Found: ' + path);
103+
return true;
104+
}
105+
logger.info('Dir NOT Found: ' + path);
106+
return false;
107+
}
108+
}
109+
}
110+
return proxyHost;
111+
}
112+
}

src/server/project.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/// <reference path="lsHost.ts"/>
55
/// <reference path="typingsCache.ts"/>
66
/// <reference path="builder.ts"/>
7+
/// <reference path="g3ServerHostProxy.ts"/>
78

89
namespace ts.server {
910

@@ -119,6 +120,8 @@ namespace ts.server {
119120
// wrapper over the real language service that will suppress all semantic operations
120121
protected languageService: LanguageService;
121122

123+
public readonly proxyHost: ServerHost;
124+
122125
public languageServiceEnabled = true;
123126

124127
protected readonly lsHost: LSHost;
@@ -202,7 +205,18 @@ namespace ts.server {
202205

203206
this.setInternalCompilerOptionsForEmittingJsFiles();
204207

205-
this.lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken);
208+
// Create a proxy server host that uses the files list to respond to
209+
// fileExists and directoryExists so as to avoid going to the
210+
// file system every time.
211+
this.proxyHost = this.projectService.host;
212+
if (projectKind === ProjectKind.Configured && hasExplicitListOfFiles) {
213+
this.proxyHost = getG3ServerHostProxy(
214+
projectName,
215+
this.projectService.host,
216+
this.projectService.logger);
217+
}
218+
219+
this.lsHost = new LSHost(this.proxyHost, this, this.projectService.cancellationToken);
206220
this.lsHost.setCompilationSettings(this.compilerOptions);
207221

208222
this.languageService = ts.createLanguageService(this.lsHost, this.documentRegistry);
@@ -727,7 +741,7 @@ namespace ts.server {
727741
}
728742

729743
const allFileNames = arrayFrom(referencedFiles.keys()) as Path[];
730-
return filter(allFileNames, file => this.projectService.host.fileExists(file));
744+
return filter(allFileNames, file => this.proxyHost.fileExists(file));
731745
}
732746

733747
// remove a root file from project

src/server/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"scriptInfo.ts",
1818
"lsHost.ts",
1919
"typingsCache.ts",
20+
"g3ServerHostProxy.ts",
2021
"project.ts",
2122
"editorServices.ts",
2223
"protocol.ts",

0 commit comments

Comments
 (0)