vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.35k stars 27.02k forks source link

getStaticProps with { fallback: true } is very slow when spa routing. #13751

Closed itome closed 1 year ago

itome commented 4 years ago

Bug report

Describe the bug

getStaticProps with fallback: true, NextJS send json response to client after calling getStaticProps in server. In my case it takes 2s until the json response comes to browser in vercel production environment in spite of getStatipProps finishing in 100ms. This may be caused by the json response is sent after the ssg rendering in server, I think the json must be returned just after getStatiProps finished.

To Reproduce

  1. Use getStatipProps and getStaticPaths with fallback: true
  2. Request ssg page from browser.
  3. When ssg page loaded, navigate to another dynamic routing page with next/link or next/router.
  4. See the chrome dev tool to see network response.

Expected behavior

The json response returned just after getStaticProps finished in server, and SSG redering and caching is done in server after that.

Screenshots

System information

todortotev commented 4 years ago

Can you provide a repository to reproduce?

itome commented 4 years ago

This is minimum example nextjs project. -> https://github.com/itome/next-get-static-props-sample

itome commented 4 years ago

Is there any progress?

yl-flyer commented 4 years ago

In my case, i have a large data that i want display it in menu. it can take 15s to get response. i placed in getStaticProps and i noticed that navigation between pages take too much time. i don't know if i miss something, the example is similar to @itome but with fallback: false

Gregoor commented 4 years ago

I'm observing the same problem, in my case also when fallback: false, like @yl-flyer already said. It does seem to hinge on payload size, I'm looking at 15kb and ~5s load time. It's realtively swift in build mode.

I'm on Windows 10 and I also tried adding the .next folder to the Windows Defender exclusion list, which didn't solve the problem.

jaredgorski commented 4 years ago

I'm experiencing this on my site https://civdocs.us (repo: https://github.com/jaredgorski/civdocs.us) with fallback: false. (code reference: https://github.com/jaredgorski/civdocs.us/blob/master/pages/docs/%5Bdocument%5D/%5Bsection%5D.tsx#L12-L42)

I'm using getStaticProps and getStaticPaths to, hopefully, pre-render the pages at build time, so I should conceivably be getting JAMstack-type performance because everything will be static at runtime, however SPA navigation to these generated pages often pauses anywhere between 1s and 10s before finally navigating.

On https://civdocs.us, you can reproduce by navigating to https://civdocs.us/docs/the-federalist and then clicking one of the links on that page. It's intermittent, but happens with fair frequency.


Update 2021-03-16 -- Could not reproduce on my production project anymore. Did not bother to test locally, but it's interesting that this issue seems to be solved in production now.

shahruz commented 4 years ago

I'm experiencing the same thing as the initial post using {fallback: true}.

Another possible solution might be having an option like Router / Link's shallow where we can navigate to the fallback page immediately instead of blocking for getStaticProps to finish. That UX seems more inline with the benefits iSSG is designed to provide.

trompx commented 4 years ago

Also having this problem in dev mode (haven't tried in production), next js 10.0.0-rc.8 (OS : Linux), both for {fallback: true} and {fallback: false}. When only using getStaticProps I get decent response time (20-40ms). As soon as I add getStaticPaths for SSG, i get 500-700ms response time, even when I do nothing and return empty paths.

melvin2016 commented 3 years ago

I'm also having the exact problem.

stefanedberg commented 3 years ago

We're having a similar problem. Our getStaticProps will in some cases poll the API until it gets an expected response. This can take some time and we're handling it in the UI with isFallback and a specific loader for this case. However, when routing to this page it will run getStaticProps before actually performing the route change. This may be intended but we would love if it could be controlled so that we can show the fallback view of that route directly.

cyphire commented 3 years ago

I think this also might be the source of my <Link isn't working as well. Works fine when deployed to site, but in dev mode usually just sits there. Also have getStaticProps and getStaticPaths for building the blog pages....

bzin commented 3 years ago

Experiencing this a lot in a recent project.

It does look that it does not affect production but this destroys the developer experience on development when using Next.js with fallback mode set to true.

It is far from optimal. On my case, I have getStaticPaths in a [...slug].js dynamic route which means that there is navigation order in the url. To test this flow is close to impossible and I have to refresh the page many times or wait for the next page to render properly which can be quite some seconds.

Any idea when this might be picked up? I see that this is already tagged by Vercel team but not sure if will be picked up any time soon.

droplab commented 3 years ago

Having the same issue. Taking anywhere from 10s - 20s for route changes on SSG pages. We have verified the async data coming in from the CMS is super fast -- feel like it's churning through building ALL of the static pages on every page change...?

droplab commented 3 years ago

Leaving this comment in case it's helpful for anyone. I traced the issue down to the styled-icons package.

There appears to be a bug in that package with import paths. TLDR; it was importing all 20k+ icons on every hot reload, route change etc... this was resulting in egregious page load times(20+ seconds) in the dev environment as well as frequent SIGBART crashes.

stubbies commented 3 years ago

Any news on this? Having the same issue with fallback: true, takes up to 5sec for non generated paths in production.

edit: This issue is from a year ago and I assume it won't be resolved which is a shame because this feature is pretty much useless now.

v3rron commented 3 years ago

This problem still persists for me with next version 10.2.3. I have a link called "Blog" in global navigation header. The posts are fetched using SSG from ButterCMS at build time with getStaticProps and getStaticPaths.

When clicking on a link, the UI is unresponsive for 3-4 seconds before loading the page with the posts with no loading indicator.

I was trying to bypass this issue by showing a loading screen first, but the problem here is that getStaticProps doesn't work if it's nested on a deeper level than root page file.

approached commented 3 years ago

I have the same error. I also have a slow API it need 1-2 seconds.

It's so easy to reproduce the error:

export async function getStaticProps() {

    await new Promise(resolve => setTimeout(resolve, 5000))

    return {
        props: {},
        revalidate: 60,
    }
}

export async function getStaticPaths() {
    return {
        paths: [],
        fallback: true,
    }
}
approached commented 3 years ago

Solution: https://github.com/vercel/next.js/blob/canary/examples/with-loading/pages/_app.js

My Component:

import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import Loading from './Loading'

/**
 * https://github.com/rstacruz/nprogress
 * https://github.com/vercel/next.js/tree/canary/examples/with-loading
 * https://nextjs.org/docs/api-reference/next/router#routerevents
 */

export default function PageChangeEvent({ children }) {
    // prepare
    const [isPageChanged, setPageChanged] = useState(false)
    const router = useRouter()

    useEffect(() => {
        const handleStart = url => {
            console.log(`Loading: ${url}`)
            // NProgress.start()
            setPageChanged(true)
        }
        const handleStop = () => {
            console.log(`end`)
            setPageChanged(false)
        }

        router.events.on('routeChangeStart', handleStart)
        router.events.on('routeChangeComplete', handleStop)
        router.events.on('routeChangeError', handleStop)

        return () => {
            router.events.off('routeChangeStart', handleStart)
            router.events.off('routeChangeComplete', handleStop)
            router.events.off('routeChangeError', handleStop)
        }
    }, [router])

    if (isPageChanged) {
        return <Loading />
    }

    return children
}

Does it work for you?

v3rron commented 3 years ago

So the issue is still in the backlog and has not been fixed, any update on when it might get resolved?

remyb-dev commented 3 years ago

Still the same problem with next 12.0.1 very slow in dev when getStaticPaths is used in a page.

leerob commented 3 years ago

Still the same problem with next 12.0.1 very slow in dev when getStaticPaths is used in a page.

Did you see this comment?

If you're seeing slow on-demand compilation for pages using getStaticProps while running next dev, it might be from an incorrect import (or at a higher level, an incorrectly published package that's not tree-shakeable).

For example, this is extremely common with icon libraries, where you might be accidentally including thousands of icons when you're really only using one or two. This is partially why Next.js outputs the modules count in the Fast Refresh console output. So if you see a really large number there, you're trying to "hot reload" a ton of modules.

GoloisaNinja commented 2 years ago

I'm seeing this in a project with Next 12.0.4 and it's not an icon library issue from what I can tell. I'm tree shaking the icons I'm using. I have basically the same code deployed on a Gatsby project and the blog link navigation is 1-3seconds at most whereas the Next deploy is sometimes up to 15s for a blog post to initially load. It's insane, way past the bounce point. I'm using getStaticProps and getStaticPaths on an [articleId].js page.

here are the two deploys if you want to see for yourself: The Gatsby build - just select any blog article from the blog section. Article will load from a strapi cms very quickly 1-3s.

https://jcodes.page

The Next.js build - just select any blog article from the blog section. Article will take over 5s to load and in some cases can take up to 10-15s for the initial load.

https://next-devportfolio.vercel.app

Revisiting an article after it's been clicked once is very fast as cacheing kicks in. But that first click is a doozy. Basically only my second Next project - so I could be a fault at how I'm implementing something, however I've tried to follow docs, and the site is by no means complex. Would love to understand whats happening here...

ShahriarKh commented 2 years ago

https://nextjs.org/docs/basic-features/data-fetching#runs-on-every-request-in-development

In development (next dev), getStaticProps will be called on every request

GoloisaNinja commented 2 years ago

https://nextjs.org/docs/basic-features/data-fetching#runs-on-every-request-in-development

In development (next dev), getStaticProps will be called on every request

My issue isn't with dev - my examples are deployed projects in production environments.

rebzden-baracoda commented 2 years ago

I have the same feeling when using vercel deployment. I think that it's due to the fact that the vercel serverless function has to spin up to create new file and host it somewhere. I actually am wondering why do we need to specify getStaticPaths if we don't want to prerender all of the paths and would want to use the clientside rendering,

Zerebokep commented 2 years ago

I have the same error. I also have a slow API it need 1-2 seconds.

It's so easy to reproduce the error:

export async function getStaticProps() {

    await new Promise(resolve => setTimeout(resolve, 5000))

    return {
        props: {},
        revalidate: 60,
    }
}

export async function getStaticPaths() {
    return {
        paths: [],
        fallback: true,
    }
}

still slow af with next 12.2.2

alepacheco commented 2 years ago

This is still an ongoing issue, any update?

markkkkas commented 2 years ago

I measured two approaches with dynamic routing:

Is there anything I can do to improve performance?

davidthomasparks commented 2 years ago

Facing this issue as well. We might have to move to client side data fetching if this persists.

ghost commented 2 years ago

Same here. I get timeout errors after ~10s...

thanhtutzaw commented 2 years ago

Still the same problem with next 12.0.1 very slow in dev when getStaticPaths is used in a page.

It is slow in dev . But not in Production .

larsqa commented 2 years ago

Leaving this comment in case it's helpful for anyone. I traced the issue down to the styled-icons package.

There appears to be a bug in that package with import paths. TLDR; it was importing all 20k+ icons on every hot reload, route change etc... this was resulting in egregious page load times(20+ seconds) in the dev environment as well as frequent SIGBART crashes.

I'm curious as to how you have figured this out? Can you share your approach?

Alireza17224 commented 2 years ago

Same issue

cjimmy commented 2 years ago

This problem could be alleviated if there was a way to show some loading component while next/link navigating to a fallback: true page (which acts like fallback: blocking). Currently, router.isFallback isn't true when navigating via next/link to a fallback: true page.

b7011343 commented 2 years ago

I too am having this issue. In dev mode it takes extremely long to change route, but it works very quickly when deployed in production mode.

franzwilhelm commented 1 year ago

Pro tip that might help some of you out

We got a speedup of around 6 seconds on most of our static pages by doing this!! 🚀

For our application (which is a car company: https://rebil.no) we are using icons from @mui/icons-material. Turns out, when you do named imports, webpack builds the ENTIRE icon library, meaning on every single render you will have to wait for it.

In next.js you can add an option called modularizeImports in next.config.js: https://nextjs.org/docs/advanced-features/compiler#modularize-imports

This will make sure only components you need are actually imported. This goes for all imports, both locally with your own components, and with external packages. In the example below, I'm showing how this works with @mui/icons-material

Example

Before

import { Add } from '@mui/icons-material'; // the INTIRE @mui-icons-material package is built

After

// next.config.js
module.exports = {
  // ... your config here
  modularizeImports: {
    '@mui/material': {
      transform: '@mui/material/{{member}}',
    },
    '@mui/icons-material': {
      transform: '@mui/icons-material/{{member}}',
    },
  },
}

// in component:
import { Add } from '@mui/icons-material'; // Next.js resolves @mui/icons-material/Add for us, meaning that is the only built component!
fernando-clvm commented 1 year ago

I was experiencing very low page loads (10+ seconds) using NextJS 12.2.2, for pages making use of both dynamic route and getStaticProps. This happened in development mode only, production builds were OK.

I can confirm this doesn't happen anymore after upgrading to NextJS 13.4.4. Now only the first load of each page after a server restart is slow, but then the result is cached or something, and switching between pages is immediate.

timneutkens commented 1 year ago

This is one of the issues that couldn't clearly be fixed in pages and as such we kept this issue in mind when building the new App Router. Happy to share this is no longer an issue when using App Router. On top of that you can now create loading states when navigating between pages that take longer to load using Suspense or loading.js. You can learn more here: https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming.

github-actions[bot] commented 1 year ago

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.