-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Creating *.js files anywhere under the project root triggers recompilation in watch mode for big projects having an unresolved name #20934
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
Comments
@sheetalkamat can you please take a look. |
The scenario wherein if resolution has failed and you have more than 256 modules, triggering compilation is by design. It is to ensure that the resolution is done in exact same way as in when you that without watch option. And 256 is a limit (flexible but currently set to 256) to not iterate through modules and find the invalidated resolution, instead of just relying on program creation logic which in many cases has proven to be faster and have same result. (way to verify this is through @ogvolkov Having said that, can you please provide log from |
I do understand the rationale behind limiting the number of files to go through. However, the other points are not that clear, namely, (1) why the name is unresolved in the first place, even if the compilation itself succeeds, and (2) why js files are not short-circuited earlier, as they should not have any effect on a ts-only project. And I do confirm that the actual recompilation is quick and does not seem to change any files. The adverse effect we are seeing happens in the situation when there is a gulp file which compiles TypeScript first, and then processes the resulting files further, generating a lot of intermediate JS in progress. Basically, incremental compilation messages flood all the output, making it very hard to find a meaningful messages from the other steps of the pipeline. And no doubt they confuse developers a lot. Below is the output of tsc --watch --diagnostics, but also please note I've linked a sample project which you can use to debug the issue. The first two "Synchronizing program" outputs happen when I start tsc watch, the third one happened when I've added a new js file. c:\development\ts-mystery-watch-issue>node_modules.bin\tsc --watch --diagnostics 11:29:00 PM - File change detected. Starting incremental compilation... Synchronizing program 11:29:25 PM - File change detected. Starting incremental compilation... Synchronizing program |
It is tracking any file additions that precede over the the currently resolved resolution, again instead of watching every single file that is needed, we use directory watcher to figure out if addition to files could potentially result in new program
Technically we could do this but we chose to rather to cache this info at resolution level rather than resolutions that could change the program structure. Eg. if you didnt have
Note that #20427 did work to clear out console before reporting updated compile status and that would help you with the issue you are facing about not being able to locate useful message. |
So, if I understand correctly, even in the case of a successful resolution, you still have to watch for other potential locations because another resolution might appear there, potentially changing the compilation result. That is reasonable. I also understand how having a single recursive watcher might be more efficient than having many more specific ones. But I'm not convinced about the lack of filtering after a file change is detected. The documentation makes an impression that only TypeScript files should matter (it only talks about .js for the original Node.js resolution method, as a reference). Moreover, "Node" resolution strategy appears to be looking only in (various) node_modules, while in fact even if I put "moduleResolution": "Node" in tsconfig, recompilation is still triggered by the files appearing in other folders. In my point of view, the actual resolution order is pretty confusing if you compare with what is written in the documentation. I can imagine a situation when typings are missing/incorrect, and the compiler picks up a rogue jquery.js from a totally unexpected location under the root, confusing the hell out of a developer. I think having at least an option of consequential ts-only resolution strategy would be pretty beneficial. |
@ogvolkov Note that filtering on js file is not going to solve your purpose since you are also emitting declaration files.. So the compilation would get triggered by the declaration emit as well. We could tweak this little further to ignore the build outputs and that might help with your issue. |
…f program emit files Handles #20934
…f program emit files Handles microsoft#20934
* origin/master: (114 commits) LEGO: check in for master to temporary branch. LEGO: check in for master to temporary branch. Enable substitution for object literal shorthand property assignments in the system transform (microsoft#21106) Skip outer expressions when checking for super keyword in binder (microsoft#20164) Group intersection code in getSimplifiedIndexedAccessType Use filter instead of unnecessary laziness Remove mapped types to never from intersections Handle jsconfig.json in fourslash tests (microsoft#16484) Add a `getFullText()` helper method to `IScriptSnapshot` (microsoft#21155) Test Diff and Omit Keep string index from intersections in base constraint of index type LEGO: check in for master to temporary branch. Fix bug: get merged symbol of symbol.parent before checking against module symbol (microsoft#21147) Do not trigger the failed lookup location invalidation for creation of program emit files Handles microsoft#20934 Add test where emit of the file results in invalidating resolution and hence invoking recompile Parse comment on @Property tag and use as documentation comment (microsoft#21119) Update baselines push/popTypeResolution for circular base constraints LEGO: check in for master to temporary branch. Test:incorrect mapped type doesn't infinitely recur ...
TypeScript Version: 2.7.0-dev.20171230
Code
The issue happens if the project has a name that failed to resolve, and has more than 256 modules. The full demo project reproducing this behavior is available in this repo.
The important parts are as follows.
We would like to import third parties in the same way as normal TypeScript modules. For example, we use jquery type definitions and import it like this:
Assume that we have more than 256 modules like the one shown above.
The tsconfig.json is
Description:
Run TypeScript in watch mode. Add an arbitrary *.js file anywhere under the project root folder.
Expected behavior:
No compilation happens.
Actual behavior:
File change detected. Starting incremental compilation...
This issue is a combination of several factors from resolutionCache.ts.
First, somehow $ name gets unresolved (even though the code compiles perfectly). For some reason, the compiler starts to watch over potential paths where the resolution might be, see resolveNamesWithLocalCache. As one of the potential locations belongs to the root folder, it effectively starts watching for changes in the root folder, recursively.
Next, when JS file is added to the folder, the watcher is triggered. Normally failedLookupDefaultExtensions is used to filter out irrelevant file changes, but it's a constant, and
Extension.Js
is always included regardless of the project's decision not to compile js.Then, invalidateResolutions is called, the decision is made to always update the project, if module names collection is larger than
maxNumberOfFilesToIterateForInvalidation
.Therefore, adding a new JavaScript file triggers the recompilation.
The text was updated successfully, but these errors were encountered: