Skip to content

fix: respect tsconfig/jsconfig exclude patterns in file watcher #2807

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

aewing
Copy link

@aewing aewing commented Jul 27, 2025

Fix: Respect tsconfig exclude patterns in file watcher

svelte-check --watch was watching all files in the workspace regardless of what the tsconfig said to include/exclude. This caused performance issues in large projects and unnecessary diagnostics for excluded files.

What we did

  • Added getProjectConfig() to the language server to expose the already-parsed tsconfig
  • Added getWatchDirectories() to extract which directories TypeScript thinks should be watched based on the tsconfig include/exclude patterns
  • Updated the file watcher to only watch those directories instead of the entire workspace
  • Made the watcher update its watched directories when the tsconfig changes (with a 1 second debounce)

How it works

TypeScript already parses the tsconfig and figures out which directories to watch via its wildcardDirectories property - this has all the include/exclude logic already applied. We just use that instead of watching everything.

When the tsconfig changes, we diff the old and new directory lists and use chokidar's add() and unwatch() methods to update what we're watching without recreating the watcher.

@jasonlyu123
Copy link
Member

jasonlyu123 commented Jul 28, 2025

Thank you for the contribution, but this isn't the right approach. We already have tsconfig.json parsing logic in the language-server package. https://github.com/sveltejs/language-tools/blob/master/packages/language-server/src/plugins/typescript/service.ts. This file also has logic for watching directories in the include patterns that are outside the workspace root. It also watches the tsconfig.json, so you also don't need to watch svelte.config.js for changes that might change tsconfig.json.

Also, as I mentioned in #2797. I think the right approach is to watch only directories that match the include pattern. Not the other way around.

@aewing

This comment was marked as resolved.

@aewing

This comment was marked as outdated.

@aewing aewing force-pushed the fix/respect-tsconfig-excludes-in-file-watching branch 10 times, most recently from 41cd9b4 to 57e5c64 Compare August 5, 2025 23:59
@aewing
Copy link
Author

aewing commented Aug 6, 2025

@jasonlyu123 I have cleaned this up.
Added a method to get the project config from the typescript service.
Added an async getWatchDirectories to the svelte-check service in language-server.
Saved the watcher as an object property of the DiagnosticsWatcher.
On init/project reload we traverse watched directories and watch/unwatch from a heuristic diff.

- Add getProjectConfig() to language server to expose parsed tsconfig
- Process wildcard directories in svelte-check to determine watch paths
- Support both recursive and non-recursive directory watching based on TypeScript's configuration
- Handle relative paths correctly for directories outside workspace

This ensures svelte-check only watches directories included by the tsconfig, improving performance and avoiding unnecessary file watching.
@aewing aewing force-pushed the fix/respect-tsconfig-excludes-in-file-watching branch from d269e56 to 09930e2 Compare August 6, 2025 02:08
Copy link
Member

@jasonlyu123 jasonlyu123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I left some comments.

@aewing
Copy link
Author

aewing commented Aug 6, 2025

Thank you, I left some comments.

addressed feedback, thank you!

@aewing aewing requested a review from jasonlyu123 August 6, 2025 23:07
@jasonlyu123
Copy link
Member

There is another problem with this change. This will no longer watch the files that are loaded through module resolution and under the workspace root, but not under the "include" pattern. Of course, the old behaviour isn't ideal either. It should also watch files that aren't under the workspace root.

Having thought about this more, I am wondering if we should add the parent directory of these files to the result of SvelteCheck.getWatchDirectories. But this would make the check a lot more frequent. Or maybe it should be done in a callback option. The service.ts or the snapshotManager calls the callback function when a new snapshot is created. @dummdidumm, what do you think?

@aewing
Copy link
Author

aewing commented Aug 12, 2025

There is another problem with this change. This will no longer watch the files that are loaded through module resolution and under the workspace root, but not under the "include" pattern. Of course, the old behaviour isn't ideal either. It should also watch files that aren't under the workspace root.

Having thought about this more, I am wondering if we should add the parent directory of these files to the result of SvelteCheck.getWatchDirectories. But this would make the check a lot more frequent. Or maybe it should be done in a callback option. The service.ts or the snapshotManager calls the callback function when a new snapshot is created. @dummdidumm, what do you think?

Thoughts on this solution?
8b53cb8

@aewing aewing force-pushed the fix/respect-tsconfig-excludes-in-file-watching branch from 8b53cb8 to c63b64f Compare August 12, 2025 05:32
* Optional callback invoked when a new snapshot is created.
* Used by svelte-check to dynamically add parent directories to file watchers.
*/
onSnapshotCreated?: (dirPath: string) => void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onSnapshotCreated paired with a directory feels weird. It would probably be better if it sent the filename or replaced onSnapshotCreated with a more specific name.


private async updateWatchedDirectories() {
const watchDirs = await this.svelteCheck.getWatchDirectories();
const dirsToWatch = watchDirs || [{ path: this.workspaceUri.fsPath, recursive: true }];
Copy link
Member

@jasonlyu123 jasonlyu123 Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see the usage of recursive here. Did you forget to pass it to chokidar, by chance? Also, maybe the currentWatchedDirs should also keep the recursive information. This way, we can skip the directory watch if the directories were watched recursively.

Copy link
Member

@jasonlyu123 jasonlyu123 Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Chokidar doesn't support specifying recursive here. I'm fine with it always being recursive. In this case, we don't need to keep the recursive info here. We just need to check if it's under a directory we already watched.

this.watcher.add(dir);
this.currentWatchedDirs.add(dir);
// New files might now be visible; schedule a run
this.scheduleDiagnostics();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need this. If a new file is added, either it got added because of a file-watcher or it's added because of module resolution. In both ways, the file watcher should already trigger scheduleDiagnostics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants