-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
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
[discussion] Improving Jest performance with a custom resolver #11034
Comments
Oh, also I think there may be an opportunity here to improve the performance of Jest's default resolver. The resolver is currently synchronous and therefore uses resolve's synchronous method. However, I noticed that resolve's async method has a If this is the case, Jest's resolver could be made asynchronous to take advantage of this, and add some |
I'm curious if TypeScript module resolution is better than The downside is that, users are forced to install TypeScript unless another resolver package is introduced separately from current package. |
I'm surprised there's not more caching here. E.g. reading and parsing the same json file multiple times seems unnecessary. Also, crawling the file system each time resolution happens seems overkill - some short circuiting based on paths and parent paths seems like it'd solve it to at least only read/parse package.json once per directory in the project. We can implement /cc @ljharb |
An individual app, however, certainly can assume this. Perhaps |
Within a single test run I think we can make that assumption. But maybe not... Might make sense to allow users to modify this. Adding that capability to |
I’d be happy to accept a PR :-) any time i have to work on resolve directly will be focused on exports support. |
This might be a relevant starting point if someone wants to pick it up: browserify/resolve#186 |
One last comment - any API in |
The other alternative would be a wrapper package that uses |
I opened up browserify/resolve#236 which adds A further improvement might be adding a |
Above PR has been released, here's a PR using that: #11076 |
^ released in |
I'd like to investigate the aforementioned |
Agreed, I think it would only be faster if the paths could be determined quickly ahead of time and then looked up in a Set or something in the resolver. Do you happen to know if the haste map knows about package.json files and if that is accessible by the resolver? If so, maybe that information could be used here and would give a speed boost. And speaking of haste map, if we can use that for package.json perhaps we could also use it for |
Haste map has all user files, but not files in node_modules |
Gotcha. That might still be worth doing though for user files. |
Interesting, it seems like #11076 in next.3 made module resolution smarter for Angular package format that Jest no longer asks to transform Angular next.3 did help something with performance for Angular projects since |
This issue is stale because it has been open for 1 year with no activity. Remove stale label or comment or this will be closed in 30 days. |
This issue was closed because it has been stalled for 7 days with no activity. Please open a new issue if the issue is still relevant, linking to this one. |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
I work in a fairly large codebase (~80,000 TypeScript files plus ~250,000 files in node_modules), and I recently improved a performance issue we were seeing with Jest and wanted to share my findings and code somewhere that others may find useful. Please feel free to close this issue.
We are currently using Jest features like
--findRelatedTests
or--changedSince
in some places in our CI setup. I wanted to see the list of test files, so I tried this out locally with the--listTests
flag and noticed that it was very slow (~150 seconds).Here's a CPU profile I took in devtools:
Zooming in, that very large block all looks basically just like this:
I discovered that almost all of the time was spent in the
loadpkg
function of the resolve package, which Jest uses as part of its default resolver: https://github.com/facebook/jest/blob/baf9f9937720e87d2b2bd09f4c053fa4f16424ec/packages/jest-resolve/src/defaultResolver.ts#L44-L54Unfortunately, the resolve package is not very efficient for this. This package will attempt to look for
package.json
files in every directory, and repeatedly read and parsepackage.json
files, for every file that it needs to resolve: https://github.com/browserify/resolve/blob/4bece07740878577be9570efe47fde66d289b5ff/lib/sync.js#L123-L147We have some guarantees in our repo, e.g. we only have one
package.json
file outside ofnode_modules
and we don't rely on any of its fields for module resolution, and we also don't expect any of these files to change within a single run. Therefore, we can make this a lot more efficient by avoiding theresolve
package for files outside ofnode_modules
(i.e. doing a custom resolution) and caching the results. Since we have ~80,000 TypeScript files in our repo, and only onepackage.json
file that happens to be irrelevant to how these are resolved, this means we might be reading that samepackage.json
file off disk and callingJSON.parse
on its contents ~80,000 times more than is actually necessary.To ensure that the caching doesn't make watch mode confusing when the file system changes while watch mode is running, I added a watch plugin to clear the caches when the filesystem changes. This replicates the default resolver's integration with watch mode: https://github.com/facebook/jest/blob/7edfb105f3f377434d30e143a4dbcc86e541b361/packages/jest-core/src/watch.ts#L288-L289
This resolver reduces my original
--listTests --findRelatedTests
command from ~150s to ~15s.Here's my code. Most of the speed improvement is due to avoiding the resolve package for our files outside of
node_modules
, with the additional full resolution caching adding a little bit of speed improvement on top.The text was updated successfully, but these errors were encountered: