My use case is that we have a 1MB json file that is needed to render the page. No problem on the server, but we don't want to send this data to client from getInitialProps as it'll make the pagesize huge.
So, we want to SSR initially, then load the JSON file via ajax on the client and only then trigger the initial client-side hydration/render once the file has loaded.
A way to supply a promise to next/client that can awaited before the client-side hydration takes place.
If we cannot wait to delay the render, the initial SSR completes, then we have to replace it with a loading spinner on the client side while the file finishes loading. That's obviously not ideal, as it means that:
You can imagine how that gives a pretty confusing experience for the user.
I've got it working by either:
Both these ways have problems, and so I'd prefer a real solution.
I'm happy to do a PR if you can suggest me on the right approach to take.
Not saying this feature request is invalid, but here's some thoughts:
Also something to consider: as long as Next's <script type="application/json">props</script> tag is placed after the server-rendered HTML and bundle script tags, the document will render before it has finished loading. If you're seeing a white screen until the entire document has been streamed, it's likely the effect of including some other inline <script> tag (explanation).
Thanks for your replies 😊
Not saying this feature request is invalid, but here's some thoughts:
- Is there any way to slim down this json file? Maybe it can be optimized to only include things that actually appear in the page? Does it contain things like base64 encoded images that can be moved out of it?
This would be great and the best solution, but unfortunately this current structure is relied upon all through our app. There’s much legacy code that depends on it like this. It's full of category and product data, no base64. I’m not able to refactor it to the extent that’ll make a difference in the foreseeable future.
- Did you check gzipped size of the page with and without the json? If 1. is satisfied, then the json and the html should contain a lot of duplicate strings, which compresses really well. Page size would be quite big, but for network overhead, I guess gzipped size is what matters. This wouldn't help with parsing overhead ofcourse, but you seem to be primarily concerned with network overhead.
That's a good point about the gzip, I will investigate more about that. However the page size still appears > 1MB in the network tools, Lighthouse complains about it and we’re worried about the effect on SEO and bounce rates if the initial payload is massive. Maybe we could get away with it if we had to, but it’d be nice not to have to compromise.
Another alternative we’ve tried is an ugly workaround:
<div id=“next-app”> </div>It works, but React gives a mismatch warning about it, and it basically defeats the point of having hydration in the first place.
Also something to consider: as long as Next's
<script type="application/json">props</script>tag is placed after the server-rendered HTML and bundle script tags, the document will render before it has finished loading. If you're seeing a white screen until the entire document has been streamed, it's likely the effect of including some other inline<script>tag (explanation).
Thanks for the info, but unless I'm misunderstanding something I don't think this isn’t the case here and I don't see a white screen. The basic problem for me is that Next triggers the client-side render immediately, and I need a way to make it to wait for a file to load first. It happens even with no other script tags in there.
Another case for delaying hydration is conditional loading of polyfills from chunks; my attempt to inject it via Webpack customization has failed (see #8189).
Closing this as it's a non-goal for the project, and likely not necessary due to the comment in https://github.com/zeit/next.js/issues/6817#issuecomment-477655408.
If you see a white screen, double check your network trace for custom-injected scripts or CSS.
Same issue here with runtime styled-components theming.
Themes are not serializable, so I can't use getInitialProps, but I don't want to require them all in bundle, they will bloat it.
So I decided to go with conditional require on server side and with dynamic import on client, but as one would expect got blinking due to first render not having a theme yet.
So it renders properly -> React hydrates synchronously -> renders without theme (view is null in this case, can't render without theme) -> renders with theme.
On any other app, I would just load everything I need before initializing React, how can I do it with next then?
Progressive server side render might be one solution to this.
import { useEffect, useState } from 'react'
function useMounted() {
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
return mounted
}
export default function HomePage() {
const isMounted = useMounted()
return (
<main>
<section>
<h1>This section is server-side rendered.</h1>
</section>
{isMounted ? (
<section>
<h2>
This section is <em>only</em> client-side rendered.
</h2>
</section>
) : (
<p>Loading ...</>
)}
<style jsx>{`
section {
align-items: center;
display: flex;
height: 50vh;
justify-content: center;
}
`}</style>
</main>
)
}
If I understood correctly it's not solving blinking issue and not an option for me, because I have to render server side, too.
So not to ressurect closed issues I have opened a discussion about it, if anyone has any ideas please go here https://github.com/vercel/next.js/discussions/14879. If no solution will be found, I will open a feature request and PR when/if get the time.
Most helpful comment
Another case for delaying hydration is conditional loading of polyfills from chunks; my attempt to inject it via Webpack customization has failed (see #8189).