next.js icon indicating copy to clipboard operation
next.js copied to clipboard

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

Open itome opened this issue 4 years ago • 33 comments

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

  • OS: macOS, Vercel server.
  • Browser (if applies): chrome
  • Version of Next.js: 9.4.2
  • Version of Node.js: latest

itome avatar Jun 04 '20 11:06 itome

Can you provide a repository to reproduce?

todortotev avatar Jun 04 '20 11:06 todortotev

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

itome avatar Jun 04 '20 13:06 itome

Is there any progress?

itome avatar Jun 14 '20 18:06 itome

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

yl-flyer avatar Jun 19 '20 14:06 yl-flyer

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.

Gregoor avatar Jul 14 '20 08:07 Gregoor

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.

jaredgorski avatar Jul 25 '20 00:07 jaredgorski

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.

shahruz avatar Jul 28 '20 19:07 shahruz

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.

trompx avatar Nov 26 '20 11:11 trompx

I'm also having the exact problem.

melvin2016 avatar Dec 03 '20 17:12 melvin2016

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.

stefanedberg avatar Dec 14 '20 07:12 stefanedberg

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....

cyphire avatar Dec 24 '20 01:12 cyphire

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.

bzin avatar Mar 16 '21 16:03 bzin

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 avatar Mar 29 '21 23:03 droplab

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.

droplab avatar Mar 31 '21 04:03 droplab

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.

stubbies avatar Jun 22 '21 08:06 stubbies

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.

v3rron avatar Jul 25 '21 01:07 v3rron

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 avatar Jul 30 '21 16:07 approached

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?

approached avatar Aug 02 '21 10:08 approached

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

v3rron avatar Oct 26 '21 15:10 v3rron

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

remyb-dev avatar Oct 31 '21 21:10 remyb-dev

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.

leerob avatar Nov 17 '21 19:11 leerob

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...

GoloisaNinja avatar Dec 10 '21 06:12 GoloisaNinja

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

ShahriarKh avatar Dec 18 '21 17:12 ShahriarKh

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.

GoloisaNinja avatar Dec 18 '21 17:12 GoloisaNinja

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,

rebzden-baracoda avatar Jan 28 '22 09:01 rebzden-baracoda

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

Zerebokep avatar Jul 11 '22 18:07 Zerebokep

This is still an ongoing issue, any update?

alepacheco avatar Jul 13 '22 09:07 alepacheco

I measured two approaches with dynamic routing:

  • getServerSideProps cold start - 7 seconds;
  • getStaticProps + getSaticPaths - 6 seconds;

Is there anything I can do to improve performance?

markkkkas avatar Jul 22 '22 14:07 markkkkas

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

davidthomasparks avatar Jul 27 '22 18:07 davidthomasparks

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

ghost avatar Aug 13 '22 16:08 ghost