-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Elide Unused Re-exports In TSServer #40966
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
Conversation
Reminds me of this change: aws/aws-sdk-js#3398 |
I agree that being able to pull in some files without pulling in all files is a huge perf win, but I'd like to hear from someone more knowledgeable that this is a good way to achieve it. I would have guessed it had more to do with the shape of the library being imported. @gluxon Do you have numbers? Did you apply your change to a sample project and see a big perf win? |
Thanks for giving initial thoughts @amcasey!
Happy to wait for additional thoughts. The way I did it in this PR definitely needs improvements. I wrote the V0 here quickly to see what the perf differences would be and to check whether obvious problems would get caught by tests. There don't seem to be any tests failures, which I was surprised by. I think this is mostly because the files elided here are coming from project references which didn't get source code added until TypeScript 3.7 recently.
Definitely. I should add that this improved editor startup times in our monorepo specifically because we have a lot of
There's a large package on my team that got its |
It’s pretty cool that you were able to get a proof of concept working with such a small change, and it would be awesome if we could safely do something like this. Unfortunately, it could very easily break a build, and there’s (currently) no way to know whether or not it would in a particular instance without doing most of the work of a full build. There is an exact analogy to how bundlers opt into this same behavior of dead code elimination or live code inclusion—because loading JavaScript modules may have important side effects, they can’t do this in general; they have to know that the code they are omitting is “pure.” So, they read the Of course, you’re absolutely right that this behavior would often work and would often have significant benefits. It makes me wonder if, extending the bundler analogy, we could let individual packages indicate that their typings are “pure,” and enable this behavior on a per-package basis. If we had something like that, we’d probably want the authors of those packages to be able to (or have to) validate their claim that their declarations are side-effect-free: modules would not be allowed to import scripts, declare globals, or augment other modules. It’s also worth clarifying that what you’ve done here so far is not specific to TS Server, despite the PR title—which is a good thing. Including a different set of modules between |
Thanks for that fantastic in-depth explanation. We've been relying on webpack tree-shaking to reduce bundle sizes on my team, so this PR was definitely inspired by that. I wasn't aware of side-effects to the typing system through globals and module augmentations, but I see it's well-documented on typescriptlang.org and makes sense. Thanks for calling that out. It did feel like I was missing something that made this PR too easy. 😅
I'd love to explore this if the team is open to it. It sounds like the specific requirements here are to add a new flag and error on side-effectful TypeScript statements if they're seen. I'll file a new issue linking your comment to discuss that prerequisite further.
Yes, you're right. I was specifically aiming for a tsserver improvement but this does affect Ensuring errors are consistent between compilation and editing makes sense. 👍
Yup, you're right again. This PR doesn't handle
I really appreciate you and everyone else being receptive. This is a great open source community. Thanks again. |
Going to close this experiment for now. |
This is a proof of concept pull request to gather initial feedback. It should not merge and close after some discussion. I’m mostly looking for comments on whether this is viable right now.
The change applies a simple heuristic for excluding some source files from dependencies when tsserver traverses a program’s module dependency graph. If a dependency “re-exports” a file with the
export { ... } from "..."
syntax, the file of that export will not be added toProgram
if none of the identifiers are used.Suppose a package
example
uses onlySOME_CONST_A
fromexample-dep
.In this case files from
components
andutils
are no longer added. This can create big savings in memory and performance ifcomponents
/utils
loaded large dependencies themselves.Current Issues
Questions
I’m curious if the TypeScript team is willing to work with me on this change. Most of the problems with this involve handling identifiers defined in elided source files.
Identifier
s being searched for? This made calls toprocessImportedModules
a bit ugly.