-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Vite with Large Apps: Very slow initial request and slow subsequent requests #7868
Comments
Spent some time this morning trying various caching ideas, but everything I tried broke something, usually related to adding/renaming routes. There are three key things that need to be cached or sped up in some way:
Fixing 1 and 2 seemed a little easier, but the second I tried to add caching around the invalidating, everything broke -- it seems there are situations where even if the |
@dmarkow - I am going to be curious to see if "remix-react-refresh-babel" is even needed. Especially since Vite does not need Babel transforms. |
@mikekidder Vite itself may not, but Remix does use a babel transform to 1) inject react-refresh code and 2) remove server exports (loader/action/headers) from route files. |
@dmarkow Have you had success with |
@ZipBrandon I haven't explored that yet. On the old dev server my initial build time was 10-11 seconds, so Vite being at 12 for the initial build in my case is roughly the same. The caching I'm testing out right now should address the second 12 seconds where it loads in 250+ (or in your case almost 600) modules slowly. |
I think I figured out my pain points above. I ended up adding two caches. The first one is for the middleware, which checks and refreshes the cache on each request, and only invalidates the virtual modules if the config changed. This makes site navigation a ton more responsive in dev, and speeds up HDR quite a bit. The other cache is initially set in the plugin config and used anywhere there are excessive calls to So far, this caching has drastically reduced that 8.5 seconds spent in I have a patch with the caching, I'd like to use it locally for a little bit before I create a PR around this. All Vite integration tests are still passing. The only jankiness I'm seeing is that adding a new route while the server is running and then trying to navigate to it sometimes causes an error, but if I hard-reload the browser it comes up fine without having to restart the dev server. And I'm getting the same issue without my patch which may warrant a separate issue. Here's the patch if anyone wants to test -- you can use patch-package and drop it in your project's |
// Don't transform files that don't need the proxy
if (
!code.includes("@remix-run/react") &&
!code.includes("LiveReload")
) {
return;
}
// Rewrite imports to use the proxy
return replaceImportSpecifier({
code,
specifier: "@remix-run/react",
replaceWith: remixReactProxyId,
}); @pcattori Is there a reason the RefreshRuntime is being injected into every file that imports from @remix-run/react? Shouldn't it just be the root file? Making it just inject into the root route will mostly eliminate the Babel slowdown. I'm wondering if this should actually be: if (!(code.includes("@remix-run/react") && code.includes("LiveReload")) {
return;
} |
@dmarkow I'm currently trying the patch out and I'll profile on my end to see what it looks like around
|
@ZipBrandon I think that happens on the first build after changing anything in node_modules (which patch-package does). If you kill vite and start again, does it re-optimize those same dependencies again? |
@dmarkow Improvement with your patch! Yes, unfortunately if I kill vite and start again it re-optimizes it. Worse yet, if I navigate to a route that has some other dependencies that it discovers then it has to reoptimize those + all again. |
🤦 yep that looks like what we meant to write 😅 and this is why its unstable! |
An added bonus is that fixing these things drastically improves builds. Before any patches, |
@dmarkow I was running at ~5m 45s. Now 22s! |
@markdalgleish I have successfully been using @dmarkow's patch for the last 3 days. I just tried to go to nightly-20231103 where I see your change in it. My build times for prod are back to 5 minutes 45 seconds from ~22 seconds when I first patched it with @dmarkow . I didn't know if this was also due to the plugin cache that was incorporated in the patch. I carried over those changes by hand but no improvement to build times. I have currently reverted to the patched version of 2.2.0 for these performance reason but hope it can be sussed out prior to 2.2.1. |
@ZipBrandon Here is a patch file against 2.2.0 that includes the LiveReload fix. I made a PR yesterday for my other changes, so if they get accepted before 2.2.1 you won't need this patch anymore. |
I think this can be closed now that both the LiveReload fix and my caching PR are merged. |
🤖 Hello there, We just published version Thanks! |
🤖 Hello there, We just published version Thanks! |
What version of Remix are you using?
2.2.0
Are all your remix dependencies & dev-dependencies using the same version?
Steps to Reproduce
Adding per a Discord discussion with @pcattori. Given a large app with many routes and components, the first page request after starting
vite dev
can result in hundreds of network requests. In my case most pages make around 250-300 requests, but another person in that same discussion had close to 600. In addition, every following request to any route (via navigation or actions/loaders) has a significant delay (2+ seconds per page for me). Including both of these issues together since they seem closely related in the way the plugin works.Slow Initial Request
In my case, the first page request stalls for around 12 seconds while vite does its thing. After this, the app appears to load, but is not responsive for another 12 seconds while it runs 250 network requests for individual components and dependencies. This seems to be a common issue with Vite in dev mode due to the lack of bundling. But there may be some optimization opportunities on the remix plugin side.
I first ran
vite dev
and loaded a page, which let vite do it's initialnew dependencies optimized...
thing. I then restarted vite and ranvite dev --profile
, made a browser request, then loaded the profile result into speedscope.app. Looking at it in Left Heavy mode, the time spent inresolveConfig
and thenflatRoutes
is close to 9 seconds total. This is becauseresolveConfig
is being called every time the plugin is loaded, which happens for each individual request. So even though it runs relatively quickly (around 30ms in my case), it's running hundreds of times and returning the same result every time. My initial thought was to cache the results ofresolveConfig
, but adding/renaming routes will break.The next largest bottleneck in the remix plugin is at the transform function for remix-remix-react-proxy. For my initial page load, it's spending around 3-4 seconds here, most likely due to parsing the code of every single file in my project to see if it has "@remix-run/react" in it.
Slow Subsequent Requests
The
transform
bottleneck above is also causing subsequent requests to have a delay of 2+ seconds for me, which includes any navigation or calling any loaders/actions. This also slows down HMR -- even though vite almost instantly sends the updated component to the browser, rendering is paused while HDR re-runs the loader.The plugin is set to invalidate the server build on every request, which causes all of the routes to be re-transformed. Since it's only re-transforming the routes and not every component, it is only taking 2 seconds instead of 3-4 like the initial page load, but it's enough to make the app feel very sluggish in development.
I tried commenting out the code that invalidates the server modules which makes the app very responsive after the initial load. But it has the same downside as caching
resolveConfig
: I now have to restartvite dev
any time I add or rename routes. @pcattori mentioned figuring out a way to only invalidate when the changed files include routes or the config.Expected Behavior
Reasonably quick development mode. Definitely not expecting the performance of a small 3-page app, but right now it's a significant slowdown from the old remix dev server (which took around 10 seconds for the initial build/page load).
Actual Behavior
25 second initial loads and sluggish navigation on following loads.
The text was updated successfully, but these errors were encountered: