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
Running with custom module resolver is 3x slower, as resolution is invalidated by TS compiler every time #3798
Comments
@bradzacher do you happen to have any thoughts here? By any chance are you able to send this to someone from the TS team, or would you think that's more appropriate if I re-open this there? It seems that @sheetalkamat no longer works on TS (judging by her Github activity history) and I'm not sure who else I could mention here that could help. |
Hey sorry - I don't currently have a direct contact for the TS team. I believe the people we used to work with have left the company or the project. We need to re-engage with them to rebuild the relationship, but unfortunately that takes time and effort - two things we're in short supply of as volunteer maintainers. |
Following up on this a bit to clear my issue queue: @rdsedmundo we don't have the bandwidth to take a look at this 😞. If you want to start a discussion with the TypeScript folks to get a recommendation or new API for typescript-eslint, that would be great. |
Thanks @JoshuaKGoldberg, I'll try to open a parallel issue on the TypeScript repository to see if they have something to say about it, if they say it's a wontfix then I'd just close this one here too. |
Just opened microsoft/TypeScript#48057, let's see if they can help with anything. |
This is being addressed on the TypeScript side on the issue I linked above, so I believe we can close it from here. |
Awesome that they're going to investigate this on the TS side! Let's keep this issue open as we might have to take action once it's resolved, to pull in new features or whatnot. |
@JoshuaKGoldberg TS has finally closed and released a new feature on 4.92.2 that allows providing a custom |
Part of me wonders if there are actually users of this API beyond you, Edmundo. I'm not sure if us maintaining this integration provides much benefit for the wider community given the increased API surface we need to maintain, as well as the internal TS API surface we need to maintain. Examples:
I think that we probably want to remove this entirely from our API in the next major, and those few in the community that actively want this may be better off using Thoughts @JoshuaKGoldberg? |
I understand where you coming from, and as a matter of fact I'm using I wonder if we could just make a generic option, so instead of allowing individual properties to be passed ( By the way, thanks for letting me know of the TS 5.0 renaming, I wasn't aware yet. |
Yeah 😕 as much as I'd love to support this edge case, we really don't have the bandwidth to do it justice. Our budget for investigating the TypeScript integrations side of things is going to be dedicated to performance (#6575).
Interesting idea! I like it at first glance. +1 to putting the burden of logic on users. |
The issue with a generic option is that it exposes the implementation detail that we use a specific TS API internally - which we know is not always true (single run mode) and may not hold true in the future (eg #6172, #6575). For example - imagine if we did execute on one of those redesigns and create an API compatible redesign of the internals - if we had a generic "pass through" option then we wouldn't be able to ship such a refactor without a breaking change. With the patch solution users are reaching into our internals to make changes - so it's on them to update their work as we change our internals. With an option we instead have to be careful and deliberate about changing our internals, and it could restrict us. I'm not sure - personally I think that without some solid user demand I think it's best to just bow out of support. If we were some form of a native package wherein our code was locked away - an option for sure would be great! But |
@bradzacher I'm confused - your comment seems to indicate support of removing this feature & not adding in a generic option. But adding the You raise a good point in your message and have persuaded me it's in our best interest not to add the generic option (or at least table the investigation until the performance/rearchitecture investigations all settle). Given that the only consumer on this thread is already using |
OH #6609 🤦 I see what you mean by |
Preface
I'm opening this here more as a discussion because the repo doesn't have the Discussions feature enabled, as this might be a problem to be fixed on the TypeScript compiler itself. See the Additional info for more context.
Repro
Any repo that provides a custom module resolver suffers from this, I tried in different projects and got the same results.
The actual implementation of the
resolveModuleNames
can be as simple as(moduleNames) => moduleNames.map(n => undefined)
and it is still way slower.Expected Result
Should run with similar speeds.
Actual Result
Runs 3x slower because the resolution is invalidated over and over again.
Additional Info
I have a custom module resolver with cache, and running
@typescript-eslint
with it presents a 3x slowdown compared to using TS's native resolution. I've debugged it a bit (with my limited knowledge about the TS compiler) and found that the root cause may be that the TS compiler is invalidating all the resolutions whenever a new file is checked because the Program is re-synchronized and re-created no matter what, as a custom module resolution was provided.Even though my custom
resolveModuleName
has cache and returns the cached paths immediately after the first seconds of running, the overhead of invalidating all the resolutions and re-creating the Program several times is still way too great and causes this significant slowdown.Paging a couple of folks that I'd appreciate any input here on whether there's something we can do in the @typescript-eslint side to avoid this, or a suggestion of what could be changed on the TS compiler side to better accommodate custom resolutions and invalidations.
@bradzacher because you were involved with the module resolution issue.
@uniqueiniquity because you added the original custom Program support and may have some insights on this.
@sheetalkamat because you originally introduced the
userProvidedResolution
check on the TS compiler.Example run:
Original TS
synchronizeProgram called 1047 times
createNewProgram called 1 times
resolveModuleNames called 1744 times
Custom module resolution
synchronizeProgram called 1047 times
createNewProgram called 1047 times
resolveModuleNames called 1,766,289 times
Custom module resolution with TS compiler patched, forcing the variable userProvidedResolution=false
synchronizeProgram called 1047 times
createNewProgram called 1 times
resolveModuleNames called 1687 times
Workaround
Creating a custom
ts.Program
by hand and passing it throughparserOptions.programs
.Versions
@typescript-eslint/typescript-estree
4.29.3
TypeScript
4.3.2
node
4.17.0
The text was updated successfully, but these errors were encountered: