Skip to content

Commit 42e6860

Browse files
committed
Share extended config watchers across projects in server
New shared watcher map in ProjectService that stores callbacks per project to be invoked when the file watcher is triggered. The FileWatcher is created with the watch options of the first Project to watch the extended config.
1 parent ae50345 commit 42e6860

File tree

4 files changed

+83
-38
lines changed

4 files changed

+83
-38
lines changed

src/compiler/watchPublic.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ namespace ts {
792792
}
793793

794794
function watchExtendedConfigFiles() {
795-
const configFile = builderProgram.getCompilerOptions().configFile;
795+
const { configFile } = builderProgram.getCompilerOptions();
796796
if (configFile) {
797797
updateExtendedConfigFilesWatch(
798798
configFile,

src/compiler/watchUtilities.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,73 @@ namespace ts {
282282
);
283283
}
284284

285+
export interface SharedExtendedConfigFileWatcher<P> {
286+
watcher: FileWatcher;
287+
callbacks: ESMap<P, FileWatcherCallback>;
288+
}
289+
290+
export function updateSharedExtendedConfigFilesWatch<P>(
291+
project: P,
292+
projectCallback: FileWatcherCallback,
293+
configFile: TsConfigSourceFile,
294+
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>,
295+
watchFactory: WatchFactory<WatchType, any>,
296+
watchOptions: WatchOptions | undefined
297+
) {
298+
const extendedSourceFiles = configFile.extendedSourceFiles || emptyArray;
299+
const newSharedExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue);
300+
301+
sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
302+
if (newSharedExtendedConfigFilesMap.has(key)) {
303+
existingWatcher.callbacks.set(project, projectCallback);
304+
}
305+
else {
306+
existingWatcher.callbacks.delete(project);
307+
if (existingWatcher.callbacks.size === 0) {
308+
sharedExtendedConfigFilesMap.delete(key);
309+
closeFileWatcherOf(existingWatcher);
310+
}
311+
}
312+
});
313+
314+
newSharedExtendedConfigFilesMap.forEach((_true, extendedConfigPath) => {
315+
if (!sharedExtendedConfigFilesMap.has(extendedConfigPath)) {
316+
const newWatcher = createSharedExtendedConfigFileWatcher(extendedConfigPath);
317+
sharedExtendedConfigFilesMap.set(extendedConfigPath, newWatcher);
318+
}
319+
});
320+
321+
function createSharedExtendedConfigFileWatcher(extendedConfigPath: string) {
322+
const callbacks = new Map<P, FileWatcherCallback>();
323+
callbacks.set(project, projectCallback);
324+
const watcher = watchFactory.watchFile(
325+
extendedConfigPath,
326+
invokeProjectCallbacks,
327+
PollingInterval.High,
328+
watchOptions,
329+
WatchType.ExtendedConfigFile
330+
);
331+
return { watcher, callbacks };
332+
333+
function invokeProjectCallbacks(fileName: string, eventKind: FileWatcherEventKind) {
334+
return callbacks.forEach((callback) => callback(fileName, eventKind));
335+
}
336+
}
337+
}
338+
339+
export function removeProjectFromSharedExtendedConfigFilesWatch<P>(
340+
project: P,
341+
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>
342+
) {
343+
sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
344+
existingWatcher.callbacks.delete(project);
345+
if (existingWatcher.callbacks.size === 0) {
346+
sharedExtendedConfigFilesMap.delete(key);
347+
closeFileWatcherOf(existingWatcher);
348+
}
349+
});
350+
}
351+
285352
/**
286353
* Updates the existing missing file watches with the new set of missing files after new program is created
287354
*/

src/server/editorServices.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,9 @@ namespace ts.server {
756756
/*@internal*/
757757
readonly watchFactory: WatchFactory<WatchType, Project>;
758758

759+
/*@internal*/
760+
private sharedExtendedConfigFilesMap = new Map<string, SharedExtendedConfigFileWatcher<Project>>();
761+
759762
/*@internal*/
760763
readonly packageJsonCache: PackageJsonCache;
761764
/*@internal*/
@@ -1385,6 +1388,7 @@ namespace ts.server {
13851388
project.print(/*writeProjectFileNames*/ true);
13861389

13871390
project.close();
1391+
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
13881392
if (Debug.shouldAssert(AssertionLevel.Normal)) {
13891393
this.filenameToScriptInfo.forEach(info => Debug.assert(
13901394
!info.isAttached(project),
@@ -2157,15 +2161,24 @@ namespace ts.server {
21572161
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader);
21582162
if (lastFileExceededProgramSize) {
21592163
project.disableLanguageService(lastFileExceededProgramSize);
2160-
project.stopWatchingExtendedConfigFiles();
21612164
project.stopWatchingWildCards();
2165+
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
21622166
}
21632167
else {
21642168
project.setCompilerOptions(compilerOptions);
21652169
project.setWatchOptions(parsedCommandLine.watchOptions);
21662170
project.enableLanguageService();
2167-
project.watchExtendedConfigFiles();
21682171
project.watchWildcards(new Map(getEntries(parsedCommandLine.wildcardDirectories!))); // TODO: GH#18217
2172+
if (compilerOptions.configFile) {
2173+
updateSharedExtendedConfigFilesWatch(
2174+
project,
2175+
(fileName) => this.onExtendedConfigChangedForConfiguredProject(project, fileName),
2176+
compilerOptions.configFile,
2177+
this.sharedExtendedConfigFilesMap,
2178+
this.watchFactory,
2179+
this.hostConfiguration.watchOptions,
2180+
);
2181+
}
21692182
}
21702183
project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides);
21712184
const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles());

src/server/project.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,8 +2055,6 @@ namespace ts.server {
20552055
export class ConfiguredProject extends Project {
20562056
/* @internal */
20572057
configFileWatcher: FileWatcher | undefined;
2058-
/* @internal */
2059-
private extendedConfigFileWatchers: ESMap<string, FileWatcher> | undefined;
20602058
private directoriesWatchedForWildcards: ESMap<string, WildcardDirectoryWatcher> | undefined;
20612059
readonly canonicalConfigFilePath: NormalizedPath;
20622060

@@ -2270,38 +2268,6 @@ namespace ts.server {
22702268
this.projectErrors = projectErrors;
22712269
}
22722270

2273-
/* @internal */
2274-
createExtendedConfigFileWatcher(extendedConfigFile: string): FileWatcher {
2275-
return this.projectService.watchFactory.watchFile(
2276-
extendedConfigFile,
2277-
(fileName) => this.projectService.onExtendedConfigChangedForConfiguredProject(this, fileName),
2278-
PollingInterval.High,
2279-
this.projectService.getWatchOptions(this),
2280-
WatchType.ExtendedConfigFile,
2281-
this
2282-
);
2283-
}
2284-
2285-
/* @internal */
2286-
watchExtendedConfigFiles() {
2287-
const configFile = this.getCompilerOptions().configFile;
2288-
if (configFile) {
2289-
updateExtendedConfigFilesWatch(
2290-
configFile,
2291-
this.extendedConfigFileWatchers || (this.extendedConfigFileWatchers = new Map()),
2292-
(extendedConfigFile) => this.createExtendedConfigFileWatcher(extendedConfigFile),
2293-
);
2294-
}
2295-
}
2296-
2297-
/* @internal */
2298-
stopWatchingExtendedConfigFiles() {
2299-
if (this.extendedConfigFileWatchers) {
2300-
clearMap(this.extendedConfigFileWatchers, closeFileWatcher);
2301-
this.extendedConfigFileWatchers = undefined;
2302-
}
2303-
}
2304-
23052271
/*@internal*/
23062272
watchWildcards(wildcardDirectories: ESMap<string, WatchDirectoryFlags>) {
23072273
updateWatchingWildcardDirectories(
@@ -2326,7 +2292,6 @@ namespace ts.server {
23262292
this.configFileWatcher = undefined;
23272293
}
23282294

2329-
this.stopWatchingExtendedConfigFiles();
23302295
this.stopWatchingWildCards();
23312296
this.configFileSpecs = undefined;
23322297
this.openFileWatchTriggered.clear();

0 commit comments

Comments
 (0)