Dynamic SSG/SSR styling with Next.js

Jeff Mendez
5 min readFeb 3, 2020

--

Server-side rendering has come in and out of popularity over the years with a weird reason for going out of the current meta. The power of rendering your content on the server brings the ultimate ability to target users regardless of their network connection, device capabilities, etc. It has a purpose way beyond being the flavor of the month and here's why.

The problem

The first thing that happens when a browser interacts with a domain is it checks to see if the page is in the cache to render the view that you have downloaded/been to before. Afterward, the HTML code is sent with the CSS and javascript scripts to execute to display your content which can take a couple of round trips to fully gather the assets/scripts needed for your views. This can take a long time if your network is spotty, slow or just in a remote location like the Amazon rain forest where it takes a long time for data to travel unless we are using CDNs to target broader regions (we still might have a lot of problems in the amazon with this). If your user is visiting your webpage for the first time it can take a bit of time to gather all the resources needed until its cached.

Next.js to the rescue

Next.js is a really powerful framework for react to render content on the server statically and dynamically. Next.js provides an _app and _document setup where your content first initially renders on the server firing methods on your _document file which is, in essence, the base layer that redirects all routes and API requests onto your pages. The _app file will be the initial location where your app loads on the client-side. When it comes to creating dynamic content on the server you need to make sure you mimic all client-side initial renders on the server. If you have a view that only displays on mobile devices you need to determine if its a mobile device on the _document file using different techniques since we do not have a window or DOM object to work with but, we do have metadata that is passed onto each request from the initial client interaction request. Example we can use https://github.com/faisalman/ua-parser-js to determine the agent/device on the server and set the appropriate conditional rendering for our tree.

The hard part

With great power comes great responsibility is a very true statement. Now that we see the power of next.js app-doc link setup to render SSR pages we need to understand if we do not pass down the same variables down your component tree your page styles will break and display a very ugly page to your users. We need to make sure that our top-level component and its children can execute the first render initial the same way on the client on the server which can be very tricky. I prefer to use one object that handles all conditionals that have an init process that must be equivalent from the SSR render and client init renders. The init process is usually established in the constructor of your _app and _document javascript files.

Cookies Ftw

Cookies where invented to send information on every request so that information of the users state can be tracked. If we add a middle handler that can determine whether to use the document or req data from the server we can now create dynamic views very easily. The one thing we need to do is make sure to establish an initial cookie load in our constructor or componentDidMount methods of _app.js and _document.js Here is an example of a method being used inside getInitialProps establishment for _document.js. The example below using the ua-parser-js lib and a custom parseCookie method that can either use a cookie or the dom to extract properties. I recommend using a method without UA like checking for maxTouchPoints, theres a section on how in this article.You can get very creative on how you want to store and set up your cookies for extraction.

example on _document.js getInitialProps

with-cookie package

So all this cookie talk got me wondering what if there's a way just to use your normal data structure and automatically map the property to a cookie. Also, why can't we just retrieve the same value as a cookie without having to write verbose code? You can now with https://github.com/A11yWatch/with-cookie. Heres an example being used to change the theme and persist it across documents/reloads.

you can also check out or fork the example project here https://github.com/A11yWatch/with-cookie-example

Dynamic SSG Styling — hardmode

It could be really tricky to setup your pages dynamic without the ability to return headers. For this situation we use CSS media queries to determine the initial look. If you have components like Material UI’s drawer, you would need to override the classes object on the component and set the styles attached to media quarries. On the components that you have overwrote the styling you then need to have a trigger like useEffect or componentDidMount to wipe off the extra css overrides with the initial look of the application which could be simply just assigning the props using client side detection since the page is already loaded. This is can be very complicated so weigh in the cost if it makes sense just to render the page with SSR by using getInitialProps on the component.

Conclusion

Ensuring your views to be fully dynamic SSR can be a challenge but using Next.js definitely makes it a lot easier. It also does add a layer of complexity when it comes to making a simple website. While it does bring a lot to the table in a positive manner its also important to take note of the cons as well. I highly recommend putting Next.js on a standalone server so that way it can be scaled out more efficiently since it's going to be handling a lot more work then standard client-side frameworks integrated into your application. I will go more into detail about scaling and measuring micro-services in my next article.

More
If you want to hear how I used next.js to get a perfect lighthouse score https://jeffmendez.medium.com/the-road-to-a-perfect-lighthouse-score-fe2607719b0f

--

--