This will include practices with other popular packages as well. Since NextJS really isn't your out-of-the-box React it will take some maneuvering to set up some things which need to work smoothly with SSR pages.
Disclaimer : Please come here after going through the docs at least briefly.
TOC
- Project Structure Example
- Paths
- Image optimization
- Environment variables
- Authentication
- Dynamic Imports
- Router Loading times
- GraphQL Clients
Project Structure Example
Paths
Create a jsconfig.js
file for this. Have aliases for the paths so nesting imports don't occur.
Your imports will be much cleaner and it's easy to move files or change names as everything is absolute.
Image optimization
If you are under the assumption that Next Images cannot optimize images dynamically, you're mistaken, we can optimize images coming from FE S3 or even S3 links which are attached from an API.
We will have to do the following inside next.config.js
β
You can read more about it here.
Environment variables
This is going to be a mixed bag. You can handle this in two ways :
- In
next.config.js
itself -
We can see here there's just a lot of unnecessary things going on along with the fact β Even sensitive keys are exposed and in the codebase itself.
- Look into creating the normal
.env.local
file and having your keys there. There are some guidelines which you can check here. - If you are having CI/CD processes, try to come up with an encryption flow for the
env
keys. We have this documented here for Unschool.
Authentication
There would be some situation for authenticated pages or in general a lot of logic required from an SSR function on the server. To keep things organized always return the response from a separate file like ssr.js
- For cookies, we handle the logic on server-side as well. One more thing you can leverage is β If you're using SSR, keep in mind you can opt-in for server side cookies!
- This is much more secure as it's
HTTP
only and avoids XSS attacks. - We can easily do this by writing some
Node.js
code inside our/api
folder. - Login :
- Logout :
- Keep in mind to secure the
/api
pages as anyone can access them. You can have a hex key here to protect it and redirect it to a 403 if the key isn't passed while making the request. - From the FE you can just hit the end-point β
/api/login
using fetch, if you want to use the login and logout actions on the server itself, then use a package called isomorphic-unfetch.
Dynamic Imports
There will be situations when using some packages or even Font Awesome Kits, where there will be a mismatch of rendered HTML on the client-side vs server-side.
Example :
This is mostly because the package is not designed or coded to render the right HTML code on the server-side but it renders correctly on the client-side.
For these situations + for a situation where you know you can import components / packages only when needed β You can use Dynamic imports.
- For the server-side mismatch errors, please include
ssr: false
while dynamically importing components.
Router Loading times
We will have to keep in mind if you're using SSR with all page queries on the server-side, yes there will be no loading screens needed, but let's say you want to go from one authenticated page to another, where both have page queries and some logics β This will take some time on the first
load.
- From the second load, depending on which GraphQL client you are using β Say for example Apollo GraphQL which supports server-side GraphQL queries, these will get cached.
- On redirecting or going to another route, Next JS will handle this by staying on the current page whilst it makes the queries and loads the new page, then redirects, very similar to
blocking
mode present in other data fetching methods. - It is around 1-1.5 seconds. For this, we would need to handle it properly as it can be a bad UX.
- Handle this by listening to Router events on the
_app.js
file. By Router, I mean fromnext/router
- Have a progress bar on the top of the page. You can use a good library called nprogress for this.
GraphQL Clients
As mentioned in the Starter Guide, this can be of two ways. We are going to see the Apollo client as it is more complex with SSR queries.
- Caching, the main thing we want here is server-side queries and client-side queries to be cached.
- Before looking into the code below, understand the below code solves the issue of β Setting Authentication headers when executing queries from the server-side.
- We have to keep in mind the server doesn't have access to local storage or redux or any of these things.
An example query would be β
- This function gets used in getServerSideProps, please check Authentication.