-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Slow initial page render #23187
Comments
Not all pages are loaded intentionally as when you start scaling |
What type of scaling do you mean? So far, I can only imagine a few instances of a large application, requests between which are distributed by an external load balancer, depending on the url mask. But I'm not sure if this is a common practice. In this case, it makes more sense to do something like a multi-zone application. Other types of scaling are not strictly limited to the list of available pages, I think. |
I've resorted to using @gwer 's workaround, as our app has very little traffic, only 2 pages, and scales down to 0. Dependecy import upon request means additional latency on top of cold start, which isn't great. Would love an option to handle pre-import without having to use a custom server ! Or better yet a to control what gets "lazy loaded" or not. In the meantime, thanks @gwer ! |
Do you really care about such a performance drawdown? This is a really big problem that even shows up on an empty example. And this problem has a fairly simple solution. It is enough to preload _app and _document, and also to have an additional option to preload all modules. PR #23261 closes the first part of the problem. PR #23196 could be improved to make users' lives better. But both PRs were closed. |
Hi, we definitely do care about performance and have investigated how loading of modules impacts request timings, we have actually seen the opposite and lazily loading only needed modules creates a more optimal experience especially when you're deploying on scalable infrastructure and you need to be able to start up new instances very fast to handle increasing request counts. The pre-warming seems to help a very specific case of To reconfirm our previous testing I tested some medium sized pages on the latest version of Next.js and with no pre-warming the TTFB for the first request was under 80ms and subsequent requests were under 20ms. Can you provide additional information on how you are deploying your application? Is the disk access being restricted/slowed in your environment? As mentioned on this PR there are different types of pages and assets in Next.js where this doesn't provide a speed-up and instead slows down the boot-up time for serving those assets such as automatically statically optimized pages, prerendered pages, and API routes. |
Thanks for the answer! And thanks for explain about different types of pages and assets. What about optional preloading? For example, adding a parameter to ServerConstructor. Individual simple pages do not show any noticeable slowdown. But JS is famous for its immense volumes and memes about the size of node_modules. And with the development of the application, the number of modules increases. Obviously, the problem is most important for large and complex applications, not for simple pages. 1.5s TTFB with |
Yeah It could potentially be an experimental option in |
I added an experimental option to the Should I create a new PR? Or do we need more discussion? |
I think we should start with adding an experimental config in the PR I re-opened pre-warming specifically |
I have now added experimental.prewarmRequiredPages for _app and _document prewarming in # 23261. But I think that if we want to have different options for I also want to point out that we have been using a prewarming workaround for all pages in our projects for four months now. And it works well for us. |
My team was facing a similar issue w/ long TTFB on the first page request after startup and we came across this thread. We can confirm that after hacking the experimental code from #23261 into our local Next.js server, that we see a significant drop in first page load times after startup - from ~ |
Very similarly to @chrskrchr my team saw the same thing - a whole order of magnitude reduction in TTFB when we implemented the workaround in our server for the initial page load after server spin-up. I would add my voice here in requesting for #23261 to be merged. |
Any news about this issue ? I am deploying a dummy app with Vercel and the app launches in 11 seconds which timeout for a free version. I went with a paid version but 11sec to launch a page is not acceptable. As I am using Vercel, the workaround with custom server does not apply so I would really hope for a solution from the NextJS team. Please merge the above mentioned PR 🙏 |
This is unrelated to the original question - this issue is about the local dev server Your issue could be from having a blocking request inside |
Could you share what you're importing in your |
Not really. This issue is about production too. But the workaround will work only with custom server. |
Hello @leerob , sorry for late reply. Here are my imports. They are "flattened" and obviously are spread among multiple components. // _document.tsx
import * as React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";
import createEmotionServer from "@emotion/server/create-instance";
import createCache from "@emotion/cache";
import { createTheme, responsiveFontSizes } from '@mui/material/styles'
// _app.tsx
import type { AppProps } from "next/app";
import Head from "next/head";
import Link from "next/link";
import { useRouter } from "next/router";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { createTheme, responsiveFontSizes } from "@mui/material/styles";
import { Add, Person } from "@mui/icons-material";
import { Box, Button, Grid, Typography } from "@mui/material";
import { Avatar, Button, Menu, MenuItem } from "@mui/material";
import { TextField } from "@mui/material";
import { styled } from "@mui/system";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";
import { EmotionCache } from "@emotion/utils";
import { Session } from "next-auth";
import { SessionProvider } from "next-auth/react";
import { signIn, signOut, useSession } from "next-auth/react"; If you want to experience the slowness, here it is (or more minimal version which still takes 3 seconds for an empty page). The imports for this minimal version are the following: // _document.tsx
import * as React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";
import createEmotionServer from "@emotion/server/create-instance";
import createCache from "@emotion/cache";
import { createTheme, responsiveFontSizes } from '@mui/material/styles'
// _app.tsx
import type { AppProps } from "next/app";
import Head from "next/head";
import { ThemeProvider } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { CacheProvider } from "@emotion/react";
import { EmotionCache } from "@emotion/utils";
import { SessionProvider } from "next-auth/react";
import createCache from "@emotion/cache";
import { createTheme, responsiveFontSizes } from "@mui/material/styles"; Remember that once the server is hot, it's quite fast. It's only the first hit that takes 10+ seconds. If it helps, here are the chunks for the server build: I have a ticket open with the support of Vercel which told me that it seems linked with import styles that are not treeshaken. They propose to If it can help you to troubleshoot the issue, I am willing to give you access to my repo / vercel workflow, just ask 🙂. |
@jgabriele it looks like this is from importing directly from time node -e "require('@mui/icons-material')"
node -e "require('@mui/icons-material')" 1.35s user 0.40s system 96% cpu 1.822 total |
@ijjk thanks! Indeed I get better performances now, still not ideal though. Went from 12sec to 5sec, I will try to do the same trick for Do we agree that this is a workaround though? It can't be that one person by mistake use name imports and make the page load 2.5 times slower. |
Hello, any news about this issue? I read this thread again and it looks like we have a solution ready to be merged which is opt-in so will have no impact on existing NextJS users. Is there something blocking us from merging this PR? Even with the workaround you proposed @ijjk I still see some "cold start" issues.
As you can see between the start of
|
Current state of this issue was updated in its description:
|
Changes in this PR should speed things up #50900
|
Hi, since this issue is pretty stale and generic, I'll be closing this. With regard to start-up performance, we're considering changing Next 15 to always warm up all the code on boot. You can try this out with |
This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
What version of Next.js are you using?
10.0.9
What version of Node.js are you using?
v15.11.0
What browser are you using?
Chrome
What operating system are you using?
macOS
How are you deploying your application?
next start
Describe the Bug
First render of each page has large TTFB. It can be seen in any example (e.g. api-routes-apollo-server-and-client-auth-app).
First request of localhost:3000/about has TTFB about 1–1.5s. All subsequent requests will have TTFB about 20ms. This is also reproducible if using a simple custom server.
This overhead is due to the fact that dependencies are imported on demand when the user requests a page (
next.js/packages/next/next-server/server/next-server.ts
Lines 1276 to 1280 in 27555c8
In real complex applications this overhead can increase TTFB to tens of seconds.
The second time the page loads faster, since the modules are cached (in
ssr-module-cache.js
).Module import is reading the file and interpreting the code. These are two very slow operations, especially if there is a lot of code.
Let's imagine an application with two pages: page1 and page2. It will compiled into the next 4 modules:
_app
,_document
,page1
,page2
. Using this application can be summarized as the following table._app
,_document
,page1
]_app
,_document
,page1
]_app
,_document
,page1
]page2
]_app
,_document
,page1
,page2
]You can see freeze even if page is statically optimized (because
_app
and_document
are imported even in the case of static optimization).I think some issues and duscussions about performance (e.g. #12447) is about this overhead.
But! I have a workaround. It looks like warming up the cache.
Full example:
If you run this function before starting the custom server, it will save you from overhead.
_app
,_document
,page1
,page2
]_app
,_document
,page1
,page2
]_app
,_document
,page1
,page2
]_app
,_document
,page1
,page2
]_app
,_document
,page1
,page2
]This approach has two minor drawbacks:
How about doing the same, but inside the Next.js server?
Expected Behavior
There should be no overhead for the first page rendering.
To Reproduce
Open localhost:3000/about twice and look at TTFB.
Current state (2022-09)
_app
and_document
are preimporting by default since February 2022 (#23261).For pages preimport you can use simple package next-pages-preimport.
The text was updated successfully, but these errors were encountered: