Skip to content
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

Watch mode: git diff on macOS triggers rebuild #52876

Closed
OliverJAsh opened this issue Feb 20, 2023 · 9 comments Β· Fixed by #56403
Closed

Watch mode: git diff on macOS triggers rebuild #52876

OliverJAsh opened this issue Feb 20, 2023 · 9 comments Β· Fixed by #56403
Assignees
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@OliverJAsh
Copy link
Contributor

Bug Report

πŸ”Ž Search Terms

  • watch

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about configuring watch

⏯ Playground Link

N/A

πŸ’» Code

Steps to reproduce:

  1. In a Git repository with the following files: main.ts and tsconfig.json:
    {
      "files": ["./main.ts"]
    }
  2. Modify main.ts so Git has unstaged changes and then run:
    $ tsc --project tsconfig.json --watch --diagnostics
  3. Finally, run git diff.

πŸ™ Actual behavior

tsc rebuilds because git diff bumps the access timestamp (see stat -x main.ts).

This is particularly problematic for me because I use lazygit which refreshes the Git diff every few seconds.

Screen.Recording.2023-02-20.at.20.07.44.2.mov

--

Output from tsc:

FileWatcher:: Triggered with /Users/oliverash/Development/temp/lazygit-refresh-tsc/main.ts 1:: WatchInfo: /Users/oliverash/Development/temp/lazygit-refresh-tsc/main.ts 250 undefined Source file
Scheduling update
Elapsed:: 0ms FileWatcher:: Triggered with /Users/oliverash/Development/temp/lazygit-refresh-tsc/main.ts 1:: WatchInfo: /Users/oliverash/Development/temp/lazygit-refresh-tsc/main.ts 250 undefined Source file
Synchronizing program

πŸ™‚ Expected behavior

tsc should not rebuild when the access timestamp changes.

I suspect this is due to the behaviour of fs.watch. In that case, is there anything else we can do to improve the default behaviour for macOS users? (Assuming this issue only occurs on macOS because I haven't been able to test on other platforms.)

Note I am able to workaround by setting any of the following variables in my shell RC file:

export TSC_WATCHFILE=DynamicPriorityPolling
export TSC_WATCHFILE=PriorityPollingInterval
export TSC_WATCHFILE=UseFsEvents
export TSC_WATCHFILE=UseFsEventsOnParentDirectory
export TSC_NONPOLLING_WATCHER=true
@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Feb 21, 2023
@jakebailey
Copy link
Member

#52535 feels related, if Windows suffers from the same problem with the new watching (though that example is node_modules).

@ikesau
Copy link

ikesau commented Mar 10, 2023

I can confirm that git diff started triggering this for me (which was happening every time I switched to VSCode) and that export TSC_WATCHFILE=DynamicPriorityPolling fixed it. Thank you @OliverJAsh !

@FDIM
Copy link

FDIM commented Mar 18, 2023

There is something odd going on with watching after update to typescript 4.9.5 from 4.8.4. VScode became barely usable (due to tsserver being used in multiple extensions) and after some debugging I managed to track down that it is file system changes that causes tsc to recompile/update.

More specifically it is fs.watch emitting a change event for a file in node_modules/**/package.json when tsc runs. Why that happens I have no idea.

Coincidently I was working on a little related feature in the project, and just for fun added fsPromises.watch('./node_modules/htmlparser2/package.json') and got quite surprised that I started getting events when tsserver inside vscode extension was running!

Now solution was to add this in the config:

    "watchOptions": {
        "watchFile": "dynamicPriorityPolling",
        "excludeDirectories": ["**/node_modules", "**/.angular", "**/.git"],
    },

Let me know if I can debug something more specifically. I'm experiencing this issue on Windows 10 and Node 16/18.

Now I only have to figure why lint takes 18min instead of 4min.

EDIT: This is a little crazy but somehow related to watchers or I'm misunderstanding something, runtime in CI went down from 16min to 2min!
Before:
image
After:
image

Only change is this in app tsconfig and spec tsconfig:

...
    "watchOptions": {
        "excludeDirectories": ["**/*"],
    }

@Codex-
Copy link

Codex- commented Sep 1, 2023

I can confirm this behaviour too, unfortunately, thanks for raising this already

@llllvvuu
Copy link

llllvvuu commented Sep 28, 2023

tsc rebuilds because git diff bumps the access timestamp (see stat -x main.ts).

git diff doesn't bump the Modify timestamp so maybe that would be the right thing for tsc to use

There are 3 kind of "timestamps":
Access - the last time the file was read
Modify - the last time the file was modified (content has been modified)
Change - the last time meta data of the file was changed (e.g. permissions)

https://unix.stackexchange.com/a/2803

If this is being handled purely by fs.watch then maybe this issue should be re-raised at https://github.com/nodejs/node ?

EDIT: I have confirmed this is a Node.js issue by reproducing it without TypeScript. Just filed nodejs/node#49916

EDIT 2: Update from Node.js side - wontfix working as intended. So these extraneous events will remain unless TypeScript's fs.watch handler stats the files itself. We are stuck with using other watchFile methods for now. UseFsEventsOnParentDirectory is actually quite good as it takes out much fewer watches.

@evelant
Copy link

evelant commented Nov 4, 2023

Thanks for raising this issue, it was driving me crazy and it's nice to finally know the cause. If I tried to use watch I'd get seemingly random rebuilds and ~4 rebuilds on every change.

This can get triggered by so many things. Even default vscode git integration refreshing its list of changed files causes the watcher to recompile. Or using the starship shell prompt that indicates git status, every command entered into a terminal will cause a recompile.

@sheetalkamat
Copy link
Member

sheetalkamat commented Nov 15, 2023

@OliverJAsh can you please try out #56403 (comment) to see if that helps

@OliverJAsh
Copy link
Contributor Author

I just gave it a go and unfortunately I'm getting an out of memory error.

For reference I'm coming from v5.2.2.

@OliverJAsh
Copy link
Contributor Author

I just tested this in my reduced test case and it does seem to fix the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants