Avoid Common Pitfalls with Next.js Server-Side Rendering
Common mistakes when using server side rendering that cause your application to load slow
NextJS is an amazing JavaScript framework that uses ReactJS for building UI applications. It comes with many great features that help you build faster and SEO-friendly applications like server-side rendering. However, like any tool, if used incorrectly, it can end up decreasing your performance instead of improving it. And in this article, we will cover some of the incorrect uses of server-side rendering that might cause your web application to load slower instead of faster.
1. Using slow requests in the getServerSideProps function
This function is the place where you might want to get the data required for your page component. Maybe load it from some 3rd part API, or maybe you just need to get it from your database. However, that should not take long. There should not be more than 2 seconds until your user gets to see the first items in the browser. And if your data fetching takes more than that, it is impossible to meet that criteria. Take a look at the next example.
const BadPractices = ({firstName, lastName}) => {
return (
<div>hello {firstName} {lastName}</div>
)
}
const getData = async () => {
const p = new Promise((res, rej) => {
setTimeout(() => {
res({ firstName: "john", lastName: "doe"});
},5000)
});
return p;
}
export async function getServerSideProps(context) {
const data = await getData()
return {
props: data
}
}
In the example above, we have a simple component that takes some data as props and displays them. That data is retrieved from the getData function that returns them with a timeout of five seconds. Yes, locally running this is different than running it on a server, but for the sake of the example, if there was no delay, a user would get the response in around 60 milliseconds. Because of this delay, the response is just above 5 seconds. If you have such a long-lasting request, maybe a better solution is to fetch data on the client and display some loading indicator to the user. That way user is informed that data is being loaded and the page didn’t just freeze.
2. Expensive calculations in the getServerSideProps
Your getServerSideProps function should be simple. Just a simple preparation of data and sending it to the page component. But sometimes you might be tempted to make some extra data preparation for your UI component. Be careful with that because it can heavily affect your response time.
export async function getServerSideProps(context) {
for(let i = 0; i < 100000; i++) for(let j = 0; j < 100000; j++) {}
return {
props: {firstName: "john", lastName: "doe"}
}
}
Let's take an example from the first point and just change the getServerSideProps function to the one above. You can notice two nested loops just running 100,000 times each, making its complexity of O(n^2). This makes a local delay in response of around 15 seconds. Yes, you might think that this is a nonsense example and no one would write this in the code. But you would be surprised how many times I saw developers creating even worse complexities by merging data from different sources locally and causing big performance issues.
3. Generating too large HTML
This one would also be a static generation issue, but in any case, the result HTML is so large that takes a long time to load. In the example below, I am just displaying one image, and one of the popular techniques to improve user experience is displaying placeholder images which I am using below as well.
const HeavyUI = () => {
return (
<div>hello {firstName} {lastName}
<Image
src="/DJI_0094.JPG"
alt="Picture of the dog"
fill
placeholder={"blur"}
blurDataURL={placeholderImage}
/>
</div>
)
}
For this to work, the placeholder image is converted to base64 and used for display until the correct image is loaded. The problem happens if you use the incorrect image that takes too much memory. In this example, I took the final image and directly converted it, which caused an initial loading time to be over five seconds because the full image of 4MB was injected into the HTML. Yes, an intentional mistake, but often happens that an incorrect image is used. Other reasons could generate large HTML as well. Maybe there is not one large image, but many small ones or just content generated ends up being large, like big tables or lists. These are all things you should keep in mind when using server rendering.
Wrap up
Server-side rendering (and static site generation) are great tools to improve your web application performance. And when utilized correctly, can give amazing SEO improvement. However, it is important to use it correctly. The user should have some visible response in the first 2 seconds and a longer time might even cause ranking penalties by search engine. That is why I hope this article can help you to avoid some common mistakes. The code used in the examples above can be found in my GitHub repository.
For more, you can follow me on Twitter, LinkedIn, GitHub, or Instagram.