Tag: NextJS

Data Fetching options with NextJS

When it comes to building websites in node, I'm a big fan of using NextJS. There's a lot of static site generators around but one of the things I really like about NextJS is not only the fact you have different options for data fetching, but that they're also really easy to use.

Static Generation

If you've somehow missed it, static site generation is the idea that to make your site run as fast as possible for every user, you pre-generate all the pages so that when a visitor makes a request for the page, all the server needs to do is return a file. It's a bit like the start of the internet when everything was an html file, before we became clever and started generating files dynamically on the fly. With all the processing removed, the time to first byte is greatly reduced.

To do this with NextJs you add a function called getStaticProps to your page and when the site is built, this will get all the static content and make it available to the page to be pre-generated.

export async function getStaticProps(context) {
return {
  props: {}, // will be passed to the page component as props
}
}

Or if your using TypeScript.

import { GetStaticProps } from 'next'

export const getStaticProps: GetStaticProps = async (context) => {
// ...
}

Static Generation for Dynamic Paths

So that last example would generate content for a page, but what if you have a headless CMS and unlimited pages. You certainly couldn't create a file for each one with it's own getStaticProps function.

For this there is getStaticPaths. Like getStaticProps this function will run at the build time and is used to find and return all the dynamic paths for the page. Think of your page as the page template and this function is getting all the pages that relate to it. This is how I generate all the blog post pages on this site.

The function returns an object with two values. First paths which is a list of all the routes and the parameters for them. e.g. a list of the id's to get the data for a page with. The second is fallback: false, this tells NextJs that if the request is for a route not in the paths list, then returns a 404.

export async function getStaticPaths() {
return {
  paths: [
    { params: { ... } } 
  ],
  fallback: false
};
}

The params are then passed to the getStaticProps function so that it can pre-generate all the page content.

// This also gets called at build time
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()

// Pass post data to the page via props
return { props: { post } }
}

If you'd prefer Typescript then this is the alternative.

import { GetStaticPaths } from 'next'

export const getStaticPaths: GetStaticPaths = async () => {
// ...
}

The Good Old Dynamic Way

Static's great, but sometimes are pages just aren't static enough for it to make sense. Here's where getServerSideProps comes in. With getServerSideProps your page will get generated on the server at runtime.

At this point you head may explode because at some point someone told you static site generators were faster, more secure etc because nothing runs on the server. Well erm.................. there is a server and it can generate files, so they were er... wrong.

export async function getServerSideProps(context) {
return {
  props: {}, // will be passed to the page component as props
}
}

Or with TypeScript.

import { GetServerSideProps } from 'next'

export const getServerSideProps: GetServerSideProps = async (context) => {
// ...
}

Incremental Static Regeneration

Lets take are mind back to that first static page generation. It's great for the end user, but the downside is that each time you need to change something on a page you have to regenerate the entire site. On a big site, that's an issue.

Incremental Static Regeneration lets you tell NextJs that while you want the page the be pre-built, you also want that version to expire and get generated again. Think of this like the expiry time on a CDN, but configured at a page level in your site.

To use it the getStaticProps function needs to return a revalidate value. This gives the instruction of up to how frequently the page should be generated.

export async function getStaticProps() {
const res = await fetch('https://.../posts')
const posts = await res.json()

return {
  props: {
    posts,
  },
  // Next.js will attempt to re-generate the page:
  // - When a request comes in
  // - At most once every 10 seconds
  revalidate: 10, // In seconds
}
}

Part Static Generation

So lets say we don't need our pages to expire other than when we rebuild the site, and we also don't want to generate every page in our site because there 2000 of them and it will take ages, but there's also some really important pages that we don't want any user to have to wait for.

Well if we go back to our static generation for dynamic routes example and take another look at that fallback value we can do something different.

Fallback can be set to 3 values, false, true and blocking. False will return a 404 if the route didn't exist, but true and blocking gives us an option to decide at runtime if we want to generate a page or issue a 404.

Setting fallback to true will return a fallback page, getStaticProps will then generate the page and this will then get swapped with the fallback version. Blocking is similar but will wait for the new page to be generated rather than initially issuing a fallback.

By doing this, the paths we return in the props will get generated at build time (we can restrict this to just our important pages), and all the others will function like a regular CDN.

Summary

So as you can see, there's a whole host of options to fetching data, when you do it, how you do it, how long it lives for and I didn't even cover the fact you could still fetch data dynamically when the page has loaded on the client! If we did this then we can pre-generate all the static parts of our page and then populate other bits dynamically after on the client.

JavaScript frameworks explained to an ASP.NET dev

For most of my career I've been an ASP.NET dev and a JavaScript dev. If I was going to say I was more of an expert in one of them it would be the .NET side of things but I've never really lost touch with JavaScript.

Right now I think it's fair to say technologies in the world are starting to shift how we build websites, with JavaScript frameworks reaching a point with features like static site generation where they actually now offer a decent performance incentive to use them. At some point Blazor may get to a point where it reverses this, but right now there's a compelling argument to move.

For a ASP.NET dev this can be a daunting task. You might be thinking of trying out a headless CMS with a JavaScript front end, but just take a look at this screen grab from Prismic's sdk list.

There's 7 different JavaScript based SDK's listed there! Over half of the total and none of them are that Angular thing you had heard about. Where do you start?

Lets compare to .NET

Well recently I've been updating my JS skills again trying out some of the frameworks I hadn't used before, so I thought I'd share some learnings. The good news is as always it's not really as different as it first seems. To take some of the pain out of understanding what all these frameworks are I thought it would be good to try and relate them back to .NET and what the almost equivalent is.

Assembly Code

No not actual assembler but what does our code actually compile to. In the .NET world we have CIL (Common Intermediate Language), previously known as MSIL (Microsoft Intermediate Language) that our C#, F#, VB etc all compile down to before then being converted to the correct machine code for where they run.

In the front end world think of JavaScript being a bit like this (apart from the fact you actually write JavaScript and we don't write CIL).

View Engine

To render views into HTML, in the ASP.NET world we have Razor, but not just Razor. We also have WebForm, Brail, Bellevue, NDjango (see more here), it just happens that we mostly just use Razor.

I see the equivalents of these being ReactJS, VueJS and Angular. Its not an exact match as they also aren't exact equivalents or each other, but they're largely your functionality that will take a model and turn it into HTML.

Web Application Framework

The problem with the name framework is it applies to basically anything, but this is what I'm going with for describing ASP.NET MVC/ASP.NET Razor Pages/Web Forms, you know all those things built on-top of .NET that make it a website rather than a desktop app. They do things like routing, organising our files into controller and view folders, know how to respond to http requests etc.

Here we have Next.js, Nuxt.js and maybe Gatsby. The link between these and View Engine is a bit stronger than the ASP.NET MVC world as you essentially have a one to one mapping Next.js -> React, Nuxt.js -> Vue but they are what adds routing, static site generation and organization to your code.

Lower Level Framework

Now this one could be wrong :)

In .NET we have different version of the framework. e.g. .NET Framework /3.5/4, .NET Core, .NET 5, Mono. On the front end side they have Node.

Languages

In .NET we have choices including C#, F#, VB among other.

JavaScript has JavaScript (which I know I said was assembly), TypeScript, Coffee Script maybe more.

Not so daunting

There's probably a bunch of flaws with my comparison list and reasons people can point out why things I've said are the same are in fact different, but my point was really to show that while .NET may appear as one button on a SDK list alongside 7 JavaScript based SDK's its not that different. Out of the 7 Node is based on JavaScript. Vue and React are based on Node, and Next/Gatsby/Nuxt are based on Vue/React. There just isn't the same concept of all of it being built by one company or one particular combination being dominant in the same way that ASP.NET MVC + C# + Razor has been for the last generation of .NET websites.