Skip to content

Commit cd97adb

Browse files
committed
Do not watch the parent folders recursively if not needed.
This avoids watching folders like parent folder of the project root just to watch files created in the folder Fixes microsoft/vscode#51139
1 parent 46e7cca commit cd97adb

File tree

2 files changed

+24
-17
lines changed

2 files changed

+24
-17
lines changed

src/compiler/resolutionCache.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,14 @@ namespace ts {
6060
watcher: FileWatcher;
6161
/** ref count keeping this directory watch alive */
6262
refCount: number;
63+
/** is the directory watched being non recursive */
64+
nonRecursive?: boolean;
6365
}
6466

6567
interface DirectoryOfFailedLookupWatch {
6668
dir: string;
6769
dirPath: Path;
70+
nonRecursive?: boolean;
6871
ignore?: true;
6972
}
7073

@@ -251,7 +254,6 @@ namespace ts {
251254
perDirectoryResolution = createMap();
252255
perDirectoryCache.set(dirPath, perDirectoryResolution);
253256
}
254-
255257
const resolvedModules: R[] = [];
256258
const compilerOptions = resolutionHost.getCompilationSettings();
257259
const hasInvalidatedNonRelativeUnresolvedImport = logChanges && isFileWithInvalidatedNonRelativeUnresolvedImports(path);
@@ -393,6 +395,7 @@ namespace ts {
393395

394396
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
395397
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
398+
// Always watch root directory recursively
396399
return { dir: rootDir!, dirPath: rootPath }; // TODO: GH#18217
397400
}
398401

@@ -409,11 +412,12 @@ namespace ts {
409412
dirPath = getDirectoryPath(dirPath);
410413
}
411414

412-
// If the directory is node_modules use it to watch
415+
// If the directory is node_modules use it to watch, always watch it recursively
413416
if (isNodeModulesDirectory(dirPath)) {
414417
return filterFSRootDirectoriesToWatch({ dir, dirPath }, getDirectoryPath(dirPath));
415418
}
416419

420+
let nonRecursive = true;
417421
// Use some ancestor of the root directory
418422
let subDirectoryPath: Path | undefined, subDirectory: string | undefined;
419423
if (rootPath !== undefined) {
@@ -422,14 +426,15 @@ namespace ts {
422426
if (parentPath === dirPath) {
423427
break;
424428
}
429+
nonRecursive = false;
425430
subDirectoryPath = dirPath;
426431
subDirectory = dir;
427432
dirPath = parentPath;
428433
dir = getDirectoryPath(dir);
429434
}
430435
}
431436

432-
return filterFSRootDirectoriesToWatch({ dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath }, dirPath);
437+
return filterFSRootDirectoriesToWatch({ dir: subDirectory || dir, dirPath: subDirectoryPath || dirPath, nonRecursive }, dirPath);
433438
}
434439

435440
function isPathWithDefaultFailedLookupExtension(path: Path) {
@@ -452,7 +457,7 @@ namespace ts {
452457
let setAtRoot = false;
453458
for (const failedLookupLocation of failedLookupLocations) {
454459
const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation);
455-
const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
460+
const { dir, dirPath, nonRecursive, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath);
456461
if (!ignore) {
457462
// If the failed lookup location path is not one of the supported extensions,
458463
// store it in the custom path
@@ -464,23 +469,25 @@ namespace ts {
464469
setAtRoot = true;
465470
}
466471
else {
467-
setDirectoryWatcher(dir, dirPath);
472+
setDirectoryWatcher(dir, dirPath, nonRecursive);
468473
}
469474
}
470475
}
471476

472477
if (setAtRoot) {
478+
// This is always recursive
473479
setDirectoryWatcher(rootDir!, rootPath); // TODO: GH#18217
474480
}
475481
}
476482

477-
function setDirectoryWatcher(dir: string, dirPath: Path) {
483+
function setDirectoryWatcher(dir: string, dirPath: Path, nonRecursive?: boolean) {
478484
const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath);
479485
if (dirWatcher) {
486+
Debug.assert(!!nonRecursive === !!dirWatcher.nonRecursive);
480487
dirWatcher.refCount++;
481488
}
482489
else {
483-
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 });
490+
directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath, nonRecursive), refCount: 1, nonRecursive });
484491
}
485492
}
486493

@@ -530,7 +537,7 @@ namespace ts {
530537
dirWatcher.refCount--;
531538
}
532539

533-
function createDirectoryWatcher(directory: string, dirPath: Path) {
540+
function createDirectoryWatcher(directory: string, dirPath: Path, nonRecursive: boolean | undefined) {
534541
return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => {
535542
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
536543
if (cachedDirectoryStructureHost) {
@@ -541,7 +548,7 @@ namespace ts {
541548
if (!allFilesHaveInvalidatedResolution && invalidateResolutionOfFailedLookupLocation(fileOrDirectoryPath, dirPath === fileOrDirectoryPath)) {
542549
resolutionHost.onInvalidatedResolution();
543550
}
544-
}, WatchDirectoryFlags.Recursive);
551+
}, nonRecursive ? WatchDirectoryFlags.None : WatchDirectoryFlags.Recursive);
545552
}
546553

547554
function removeResolutionsOfFileFromCache(cache: Map<Map<ResolutionWithFailedLookupLocations>>, filePath: Path) {

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8011,10 +8011,10 @@ new C();`
80118011
checkCompleteEvent(session, 2, expectedSequenceId);
80128012
}
80138013

8014-
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], directories: string[]) {
8014+
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], recursiveDirectories: string[], nonRecursiveDirectories: string[]) {
80158015
checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1);
8016-
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
8017-
checkWatchedDirectoriesDetailed(host, directories, 1, /*recursive*/ true);
8016+
checkWatchedDirectoriesDetailed(host, nonRecursiveDirectories, 1, /*recursive*/ false);
8017+
checkWatchedDirectoriesDetailed(host, recursiveDirectories, 1, /*recursive*/ true);
80188018
}
80198019

80208020
function createSessionAndOpenFile(host: TestServerHost) {
@@ -8035,22 +8035,23 @@ new C();`
80358035
const filesWithNodeModulesSetup = [...filesWithSources, nodeModulesRecorgnizersText];
80368036
const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile];
80378037

8038-
const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, withPathMapping ? packages : recognizersDateTime, ...getTypeRootsFromLocation(recognizersDateTime)];
8038+
const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, ...(withPathMapping ? emptyArray : [recognizersDateTime]), ...getTypeRootsFromLocation(recognizersDateTime)];
80398039
const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...(withPathMapping ? [recognizersText] : emptyArray), ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)];
8040+
const nonRecursiveWatchedDirectories = withPathMapping ? [packages] : emptyArray;
80408041

80418042
function verifyProjectWithResolvedModule(session: TestSession) {
80428043
const projectService = session.getProjectService();
80438044
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
80448045
checkProjectActualFiles(project, filesInProjectWithResolvedModule);
8045-
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithResolvedModule, watchedDirectoriesWithResolvedModule);
8046+
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithResolvedModule, watchedDirectoriesWithResolvedModule, nonRecursiveWatchedDirectories);
80468047
verifyErrors(session, []);
80478048
}
80488049

80498050
function verifyProjectWithUnresolvedModule(session: TestSession) {
80508051
const projectService = session.getProjectService();
80518052
const project = projectService.configuredProjects.get(recognizerDateTimeTsconfigPath)!;
80528053
checkProjectActualFiles(project, filesInProjectWithUnresolvedModule);
8053-
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithUnresolvedModule, watchedDirectoriesWithUnresolvedModule);
8054+
verifyWatchedFilesAndDirectories(session.host, filesInProjectWithUnresolvedModule, watchedDirectoriesWithUnresolvedModule, nonRecursiveWatchedDirectories);
80548055
const startOffset = recognizersDateTimeSrcFile.content.indexOf('"') + 1;
80558056
verifyErrors(session, [
80568057
createDiagnostic({ line: 1, offset: startOffset }, { line: 1, offset: startOffset + moduleNameInFile.length }, Diagnostics.Cannot_find_module_0, [moduleName])
@@ -8557,11 +8558,10 @@ export const x = 10;`
85578558
service.openClientFile(srcFile.path, srcFile.content, ScriptKind.TS, projectRoot);
85588559
checkProjectActualFiles(service.configuredProjects.get(configFile.path)!, files.map(f => f.path));
85598560
checkWatchedFilesDetailed(host, mapDefined(files, f => f === srcFile ? undefined : f.path), 1);
8560-
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
8561+
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
85618562
const expectedWatchedDirectories = createMap<number>();
85628563
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
85638564
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
8564-
expectedWatchedDirectories.set(`${projectRoot}`, 1); // failed lookup for fs
85658565
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
85668566
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
85678567
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);

0 commit comments

Comments
 (0)