One of the exciting announcements from GatsbyJS V4 is the introduction of a new rendering option: Server-side Rendering. If you’re more of a static-site person, you would probably be more excited about DSG, especially if you are working on sites that have 1,000+ pages, such as content marketing sites or blogs.
However, given the abundance of third-party APIs and server-side rendering are much of an “out-of-the-box” feature in some React meta-frameworks, I thought to try out GatsbyJS’s SSR and see if it’s user-friendly enough for my next project!
New to GatsbyJS?
If you’re new to the idea of Static Site Generation and Server-Side Rendering, be sure to check out this article: Rendering Options in GatsbyJS. You’ll get a better idea of the cons and pros of using each other and how to use different rendering techniques to complement each other.
About the Project
In this project, I will:
- explore GatsbyJS’s method of doing SSR by using the function
getServerData
, which is quite similar to NextJS’s getServerSideProps, - consume CoinGecko’s Cryptocurency API to create a listing page that shows all available crypto coins. Clicking each coin will open a single coin page. In other words, we will create dynamic pages using GatsbyJS’s SSR.
- give my little verdict about GatsbyJS’s SSR.
Before we start, here are a few materials that you can check out:
- GatsbyJS x CoinGecko SSR Starter Github Public Repository. You can fork or clone it.
- CoinGecko API Docs
- Preview of the finished project
- Quick Guide to SSR in GatsbyJS
Project Structure
The project structure is quite standard like any other React/GatsbyJS project, so we will focus only the src
folder, starting from the root directory.
For simplicity, we will only focus on the bolded files:
index.js
: Fetches top 100 crypto coins.[coinId].js
: Fetches the details of specified crypto coin, e.g. crypto name, image and description.
The index.js
To understand what’s happening on this page, let’s focus on the second half of the code first.
Right after export default IndexPage
, we see GatsbyJS’s dedicated SSR function getServerData()
, with try/catch in it.
- First, fetch a list of crypto coins from the API URL
https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=100&page=1&sparkline=false
- Store the fetched response in the constant
res
- Return an object containing
props
, usually refers to the response.
Then, let’s look at the first half of the code, especially this line:
Just like that, you can access the data as a serverData
prop inside your page component. If you console log the serverData
, you should able to see an array of coins, which you can map it and do something like this:
The code above is simplified. Essentially, we tell GatsbyJS to visit the single coin pages at this given path /coin/$\{d.id\}
. Meaning, if the id
happens to be bitcoin
, the link on local will appear as localhost:8000/coin/bitcoin
.
Let’s say if we have more than 1,000+ crypto coins, we can dynamically render the single coin pages based on the coin’s id
, which we will explore how in the next section.
The [coinId].js
We’ll need to create a new file under /src/coin
folder. You can name the file name whatever you want, but the name needs to be enclosed with brackets i.e. [filename].js
. This tells GatsbyJS that the page will be server-side rendered, and the filename
will be dynamic.
Next, let’s focus on the second half of the code again. We see the following:
Notice that this time, we pass the parameter context
into the getServerData
function to obtain the slug on single coins page. This is done by specifying context.params.whatevergivenfilename
. The params
object is elaborated in the GatsbyJS SSR documentation.
params: If you use File System Route API the URL path gets passed in as params. For example, if your page is at src/pages/{Product.name}.js the params will be an object like { name: ‘value’ }.Full Reference for Gatsby SSR
Meaning, this ensures that if we are viewing the link /coin/bitcoin
, we can obtain the slug bitcoin
and pass it to the API URL as https://api.coingecko.com/api/v3/coins/bitcoin
. Then, we can return the response as props, and use it on the first half of our code like this:
If you console log the serverData
, you should be able to see the full API response from CoinGecko.
About Image Optimisation
Unlike NextJS’s Image component, there’s currently no way to optimise API response images on demand.
Paul from GatsbyJS do suggest one workaround, loosely quoting from his tweet reply:
Use a Serverless function, and run Sharp to create the image formats. Calling from a useEffect should be intial page load is still fast
Paul is also kind enough to help implement JIMP on the API response images. You can find the code on the same repo -> [feature/use-jimp-on-images](https://github.com/fsk1997/gatsby-starter-coingecko-ssr/tree/feature/use-jimp-on-images)
branch.
Or specifically, replace the following on the ./src/pages/coin/[coinId].js
-> getServerData
function.
What the replacement code does is: resize image, convert it to grayscale and encode it as Base64 format by using JIMP. Do note that Base64 wouldn’t be anymore optimised than a JPG, as pointed out by Paul too. Read more about it here: Why “optimizing” your images with Base64 is almost always a bad idea
However, the lack of image optimisation isn’t a deal-breaker for me. I think that image optimisation should be done at the earliest phase possible. Meaning, if you’re sourcing images from a third-party APIs, the response should provide you multiple image sizes (just like CoinGecko API does). I believe that client runtime operation should be reduced to minimum for best performance.
Regardless of your implementation, if you are using normal image tag, remember to specify the width and height attributes to reduce layout shifts!
And thanks Paul for chipping in some ideas!
Verdict
As this is not a complex project, the developer experience has been delightful overall. With more css and js libraries magic, you can definitely create a full-fledge web app with GatsbyJS’s SSR.