Next.js is a React-based framework for building server-side rendered (SSR) and static site-generated (SSG) applications.
Server-side rendering (SSR) means that the initial HTML for a page is generated on the server and sent to the client, which can improve the initial page load time and allow search engines to crawl and index the page more easily.
Static site generation (SSG) means that the HTML for a page is generated at build time rather than on the server or client side, which can improve the site's performance and reduce the load on the server.
Next.js allows developers to choose between these two rendering strategies based on the specific needs of their application.
In this article, you will learn how to build a Next.js application with SSG and SSR features and deploy the app with AWS Amplify.
Prerequisites
The following are required to follow along in this post.
- Basic knowledge of React.js
- Node.js is installed on your computer to run some npm packages.
- AWS Amplify account; sign up here.
Setting up the Next.js application
To bootstrap a new Next.js application, let's run the following commands in our terminal:
npx create-next-app <project-name>
After creating the application, navigate into the project directory and start the application with the following commands: open it with your default code editor.
cd <project-name> # to navigate into the project directory
npm run dev # to run the dev server
Adding Tailwind to the Mix
Run the following commands to add tailwind, postcss and the auto prefixer and initialize tailwind and add the tailwind.config
file in your project.
npm install -D tailwindcss postcss autoprefixer
npx tailwind init -p
Next, open the tailwindcss.config.js
file at the root of our project and configure it like in the below to process every javascript and typescript file in our pages and components folder.
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};
Next, open the globals.css
file from the styles folder and import the tailwind CSS files like the below:
//globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Installing Date FNS
Install date-fns
with the below command to show the difference between the SSG and SSR pages by showing the date and time the page was last served.
npm install date-fns
Building a Server Rendered Page
Here, use the getServerSideProps()
function to fetch data from an external API at the request time in the index.js
file like below:
//pages/index.js
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch("https://fakestoreapi.com/users");
const data = await res.json();
// Pass data to the page via props
return { props: { data, timeOfLoad: new Date().toISOString() } };
}
In the snippets above, we fetched data from the fakestore API endpoint, converted the data to JSON
and returned it to the return()
function so that the component function could access it.
Next, let’s create the component function and render the data from fakestore in it like in the below:
//pages/index.js
import { formatRelative } from "date-fns";
import React from "react";
const Home = ({ data, timeOfLoad }) => {
const relativeTimeOfLoad = formatRelative(Date.parse(timeOfLoad), new Date());
return (
<div className="mx-auto w-3/4 my-16">
<div className="my-8">
<h2 className="text-6xl text-center">
Contacts from Server Side Rendering{" "}
</h2>
<p className="text-center">{relativeTimeOfLoad}</p>
</div>
<div className="grid grid-cols-2 gap-4 md:grid-cols-3">
{data.map((dt) => (
<div
key={dt.id}
className="border-2 shadow-sm border-gray-200 rounded px-6 py-4 space-y-2"
>
<h3 className="text-2xl text-gray-800 capitalize">
{" "}
{dt.name.firstname} {dt.name.lastname}
</h3>
<p className="my-4 text-lg text-gray-800"> {dt.email}</p>
<p className="my-4 text-md text-gray-800"> {dt.phone}</p>
<p className="my-4 text-sm text-gray-500 uppercase">
{" "}
{dt.address.city}
</p>
</div>
))}
</div>
</div>
);
};
export default Home;
In the snippets above, we:
- Imported
formatRelative
from thedate-fns
package installed earlier, grabtimeOfLoad
we passed from thegetServerSideProps
function and created a relative time between when the page was generated from the server and now. - Rendered a title containing the page title, looped through the
data
we passed in thegetServerSideProps
function, and displayed the user details.
Now, run npm run dev in the terminal and head over to the browser to preview the rendered user cards.
Next, let's create the SSG page to go along with the server-side rendered page we've created.
Create an ssg.js
file inside the pages folder with the following snippets:
export async function getStaticProps() {
// Run API calls in parallel
const productsResponse = await fetch("https://fakestoreapi.com/products");
const products = await productsResponse.json();
return {
props: {
product: products,
timeOfLoad: new Date().toISOString(),
},
};
}
Here, we fetched our products using the getStaticProps()
function, converted it to JSON and returned it as props.
We also attached a timeOfLoad
prop just like we did in the SSR page.
Next, create an SSG function component which'll receive the product prop like in the below:
//pages/ssg.js
import Link from "next/link";
import { formatRelative } from "date-fns";
const SSG = ({ product, timeOfLoad }) => {
const relativeTimeOfLoad = formatRelative(Date.parse(timeOfLoad), new Date());
return (
<div className="mx-auto w-3/4 my-16">
<div className="my-8">
<h2 className="text-6xl text-center">
Products with Static Generation{" "}
</h2>
<p className="text-center">{relativeTimeOfLoad}</p>
</div>
{product.map((pr) => (
<div
className="border-2 shadow-sm border-gray-200 rounded p-3 my-4"
key={pr.id}
>
<div className="space-y-2">
<p className="font-bold"> Title: {pr.title}</p>
<p> Description: {pr.description}</p>
<p className="text-lg"> ${pr.price}</p>
</div>
</div>
))}
</div>
);
};
export default SSG;
Here we rendered the head, looped through the product prop and rendered the list of products; showing each product's details.
We imported formatRelative
and repeated the process just like in the SSR page to show the relative time between when the page was sent from the server and now.
In the browser, we would confirm that the products were rendered.
Deploy to Amplify Hosting
Deploying our app with AWS Amplify allows us to test the time difference between the SSR and the SSG pages.
First, push the codes to GitHub or other preferred git providers, Login to the AWS console, search for Amplify and select it from the list of services.
Next, click on the New app drop-down and select Host Web App. Select GitHub or your Git provider on the next page and click the continue button.
Next, click on the Connect branch button, select the repository you intend to host, select the main branch and click on the Next button to proceed.
On the next page, configure the build settings and click on the Next button.
Review your settings on the next screen and click the Save and deploy button to start the deployment processes. After deploying, click on the live link provided by Amplify to access your app.
While testing the live app, notice that the SSR page always matches the current time because the getServerSideProps
function is always called when the page is refreshed.
Whereas getStaticProps
on the SSG page is called only when the page is loaded.
Conclusion
This post discussed how to build a Next.js application that includes a serverside rendered page and a statically generated page and deploy the application using AWS Amplify.