perf: async fs calls in resolve and package handling
Description
getRealPath in resolve is taking ~8% of the workload in https://github.com/yyx990803/vite-dev-server-perf, and it is calling fs.realPathSync.native. After this PR, it takes ~2% by using fsp.realPath (equivalent to the .native sync version).
I tested the speed improvement using the test in the repo instead of the cpuprofile, but it isn't stable on my machine. I think that even if we now have a ton of promises being generated, the non-blocking fs calls should still make this change worth it. We need to test in some other benchmarks.
The PR also changes a fs.readFileSync in package.ts to be async, and that triggered a whole bunch of async/await changes in the codebase too.
What is the purpose of this pull request?
- [ ] Bug fix
- [ ] New Feature
- [ ] Documentation update
- [x] Other
Run & review this pull request in StackBlitz Codeflow.
I don't know why Windows isn't happy (at least in CI) when using fsp.realPath. Using fs.realPathSync.native works, so for now we are back to sync for windows.
This makes this PR a bit more controversial, because it will mean a small regression on Windows due to the extra promises being generated. But a lot of them are needed due to the fsp.readFile change, and I ended up reducing the number of created promises at refactor: avoid creating promises in tryCleanFsResolve. So I think this may still be a good step.
If someone with more Windows knowledge finds a way to make fsp.realPath work, appreciated! But now we can also do that in another PR.
@userquin tested in his Windows machine, and d3c8f90 is working for him with the same node version as CI. @sapphi-red, maybe you could try too when you have some time? Even if it works, I don't think we can just fallback to sync for CI 🤔
It works on first run after build (pnpm test-serve), second run fails with same CI errors (node 20.10.0 LTS):
I found a bug in Node (https://github.com/nodejs/node/issues/51031) and maybe that's the culprit. I pushed a commit to use fs.realpath.native instead of fsp.realpath.
I found a bug in Node (nodejs/node#51031) and maybe that's the culprit. I pushed a commit to use
fs.realpath.nativeinstead offsp.realpath.
Woah! Amazing find @sapphi-red 👏🏼 ❤️
I'm curious to see if this PR improves the benchmarks on your machine. I don't know why there is so much variance when I measure on mine.
Here's the results of https://github.com/yyx990803/vite-dev-server-perf on my Windows machine. It's seems on a par.
before
1000 TS modules (50x20) loaded in: 1049ms (runs: [1274,1040,1060,1021,1049])
1000 TS modules (20x50) loaded in: 965ms (runs: [1008,934,946,966,965])
2000 TS modules (100x20) loaded in: 2237ms (runs: [2355,2252,2226,2237,2213])
5000 TS modules (250x20) loaded in: 5960ms (runs: [6592,6022,5874,5915,5960])
10000 TS modules (400x25) loaded in: 12265ms (runs: [13409,12106,12134,12265,12337])
after
1000 TS modules (50x20) loaded in: 1069ms (runs: [1257,1031,1051,1069,1071])
1000 TS modules (20x50) loaded in: 956ms (runs: [1033,956,971,941,946])
2000 TS modules (100x20) loaded in: 2249ms (runs: [2358,2249,2228,2191,2268])
5000 TS modules (250x20) loaded in: 5972ms (runs: [6610,5983,5936,5972,5927])
10000 TS modules (400x25) loaded in: 12152ms (runs: [13560,11932,11866,12162,12152])
I'm not sure why the "before" run is faster than the one in https://github.com/vitejs/vite/pull/15195#issuecomment-1837208126 though 🤔 .