Skip to content

Commit

Permalink
Share extended config watchers across projects in server
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
molisani committed Nov 19, 2020
1 parent ae50345 commit 42e6860
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/compiler/watchPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ namespace ts {
}

function watchExtendedConfigFiles() {
const configFile = builderProgram.getCompilerOptions().configFile;
const { configFile } = builderProgram.getCompilerOptions();
if (configFile) {
updateExtendedConfigFilesWatch(
configFile,
Expand Down
67 changes: 67 additions & 0 deletions src/compiler/watchUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,73 @@ namespace ts {
);
}

export interface SharedExtendedConfigFileWatcher<P> {
watcher: FileWatcher;
callbacks: ESMap<P, FileWatcherCallback>;
}

export function updateSharedExtendedConfigFilesWatch<P>(
project: P,
projectCallback: FileWatcherCallback,
configFile: TsConfigSourceFile,
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>,
watchFactory: WatchFactory<WatchType, any>,
watchOptions: WatchOptions | undefined
) {
const extendedSourceFiles = configFile.extendedSourceFiles || emptyArray;
const newSharedExtendedConfigFilesMap = arrayToMap(extendedSourceFiles, identity, returnTrue);

sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
if (newSharedExtendedConfigFilesMap.has(key)) {
existingWatcher.callbacks.set(project, projectCallback);
}
else {
existingWatcher.callbacks.delete(project);
if (existingWatcher.callbacks.size === 0) {
sharedExtendedConfigFilesMap.delete(key);
closeFileWatcherOf(existingWatcher);
}
}
});

newSharedExtendedConfigFilesMap.forEach((_true, extendedConfigPath) => {
if (!sharedExtendedConfigFilesMap.has(extendedConfigPath)) {
const newWatcher = createSharedExtendedConfigFileWatcher(extendedConfigPath);
sharedExtendedConfigFilesMap.set(extendedConfigPath, newWatcher);
}
});

function createSharedExtendedConfigFileWatcher(extendedConfigPath: string) {
const callbacks = new Map<P, FileWatcherCallback>();
callbacks.set(project, projectCallback);
const watcher = watchFactory.watchFile(
extendedConfigPath,
invokeProjectCallbacks,
PollingInterval.High,
watchOptions,
WatchType.ExtendedConfigFile
);
return { watcher, callbacks };

function invokeProjectCallbacks(fileName: string, eventKind: FileWatcherEventKind) {
return callbacks.forEach((callback) => callback(fileName, eventKind));
}
}
}

export function removeProjectFromSharedExtendedConfigFilesWatch<P>(
project: P,
sharedExtendedConfigFilesMap: ESMap<string, SharedExtendedConfigFileWatcher<P>>
) {
sharedExtendedConfigFilesMap.forEach((existingWatcher, key) => {
existingWatcher.callbacks.delete(project);
if (existingWatcher.callbacks.size === 0) {
sharedExtendedConfigFilesMap.delete(key);
closeFileWatcherOf(existingWatcher);
}
});
}

/**
* Updates the existing missing file watches with the new set of missing files after new program is created
*/
Expand Down
17 changes: 15 additions & 2 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@ namespace ts.server {
/*@internal*/
readonly watchFactory: WatchFactory<WatchType, Project>;

/*@internal*/
private sharedExtendedConfigFilesMap = new Map<string, SharedExtendedConfigFileWatcher<Project>>();

/*@internal*/
readonly packageJsonCache: PackageJsonCache;
/*@internal*/
Expand Down Expand Up @@ -1385,6 +1388,7 @@ namespace ts.server {
project.print(/*writeProjectFileNames*/ true);

project.close();
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
if (Debug.shouldAssert(AssertionLevel.Normal)) {
this.filenameToScriptInfo.forEach(info => Debug.assert(
!info.isAttached(project),
Expand Down Expand Up @@ -2157,15 +2161,24 @@ namespace ts.server {
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader);
if (lastFileExceededProgramSize) {
project.disableLanguageService(lastFileExceededProgramSize);
project.stopWatchingExtendedConfigFiles();
project.stopWatchingWildCards();
removeProjectFromSharedExtendedConfigFilesWatch(project, this.sharedExtendedConfigFilesMap);
}
else {
project.setCompilerOptions(compilerOptions);
project.setWatchOptions(parsedCommandLine.watchOptions);
project.enableLanguageService();
project.watchExtendedConfigFiles();
project.watchWildcards(new Map(getEntries(parsedCommandLine.wildcardDirectories!))); // TODO: GH#18217
if (compilerOptions.configFile) {
updateSharedExtendedConfigFilesWatch(
project,
(fileName) => this.onExtendedConfigChangedForConfiguredProject(project, fileName),
compilerOptions.configFile,
this.sharedExtendedConfigFilesMap,
this.watchFactory,
this.hostConfiguration.watchOptions,
);
}
}
project.enablePluginsWithOptions(compilerOptions, this.currentPluginConfigOverrides);
const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles());
Expand Down
35 changes: 0 additions & 35 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2055,8 +2055,6 @@ namespace ts.server {
export class ConfiguredProject extends Project {
/* @internal */
configFileWatcher: FileWatcher | undefined;
/* @internal */
private extendedConfigFileWatchers: ESMap<string, FileWatcher> | undefined;
private directoriesWatchedForWildcards: ESMap<string, WildcardDirectoryWatcher> | undefined;
readonly canonicalConfigFilePath: NormalizedPath;

Expand Down Expand Up @@ -2270,38 +2268,6 @@ namespace ts.server {
this.projectErrors = projectErrors;
}

/* @internal */
createExtendedConfigFileWatcher(extendedConfigFile: string): FileWatcher {
return this.projectService.watchFactory.watchFile(
extendedConfigFile,
(fileName) => this.projectService.onExtendedConfigChangedForConfiguredProject(this, fileName),
PollingInterval.High,
this.projectService.getWatchOptions(this),
WatchType.ExtendedConfigFile,
this
);
}

/* @internal */
watchExtendedConfigFiles() {
const configFile = this.getCompilerOptions().configFile;
if (configFile) {
updateExtendedConfigFilesWatch(
configFile,
this.extendedConfigFileWatchers || (this.extendedConfigFileWatchers = new Map()),
(extendedConfigFile) => this.createExtendedConfigFileWatcher(extendedConfigFile),
);
}
}

/* @internal */
stopWatchingExtendedConfigFiles() {
if (this.extendedConfigFileWatchers) {
clearMap(this.extendedConfigFileWatchers, closeFileWatcher);
this.extendedConfigFileWatchers = undefined;
}
}

/*@internal*/
watchWildcards(wildcardDirectories: ESMap<string, WatchDirectoryFlags>) {
updateWatchingWildcardDirectories(
Expand All @@ -2326,7 +2292,6 @@ namespace ts.server {
this.configFileWatcher = undefined;
}

this.stopWatchingExtendedConfigFiles();
this.stopWatchingWildCards();
this.configFileSpecs = undefined;
this.openFileWatchTriggered.clear();
Expand Down

0 comments on commit 42e6860

Please sign in to comment.