- Published on
A road to Contentful and Next.js
- Authors
- Name
- Federico Orlandau
- @fedeorlandau
Overview
With the help of this article, you'll be able to render a fully dynamic Contentful page into Next.js
Live demo: https://contentful-nextjs-tailwind.vercel.app/
Table of Contents
Choosing the right tech stack
For this starter kit we'll be using Next.js as a React framework, Vercel as a host, Tailwind as a CSS framework, and the Contentful SDK to fetch the CMS information.
Setting up Contentful
Contentful offers you a Community license that you can use for personal sites, hackathons, or philanthropic projects. The sign-up process is pretty straightforward.
We'll need to create 2 Content Types only. The first one will be the Hero
content type.
Hero
Content type ID: hero
- Title, short text. This will be entry title.
- Field ID:
title
- Field ID:
- Description, short text.
- Field ID:
description
- Field ID:
- CTA Text, short text.
- Field ID:
ctaText
- Field ID:
- CTA Link, short text.
- Field ID:
ctaLink
- Field ID:
Your Contentful model should look like this:
Page
This model will refer to each website page. We only need 3 properties to get started.
Content type ID: page
- Title, short text. This will be entry title.
- Field ID:
title
- Field ID:
- Slug, short text.
- Field ID:
slug
- Field ID:
- Components, references, many.
- Field ID:
components
- Field ID:
Entries
Now that we have our models, we need to create 2 entries. The first one is pretty easy. Just create a new Hero and fill all the properties.
For the homepage, make sure your entry looks like this:
Api keys
Finally, our last step in Contentful. Go to your settings and generate a Content Delivery Access Token.
Setting up the project
Luckily for you I've created a github repository with all the code that you need for running the project.
We'll be using degit
to clone the repository.
npx degit https://github.com/Fedeorlandau/contentful-nextjs-tailwind.git myApp
Now go into your app and create a .env file with the following content. Please replace the ***** with your actual api keys. You can find all of this information in your Contentful settings.
CONTENTFUL_SPACE_ID='*****'
CONTENTFUL_TOKEN='******'
CONTENTFUL_ENVIRONMENT='*****'
NEXT_USE_SSR=1
Now we need to install all the modules.
yarn
Finally, run your solution by doing
yarn dev
How page generation works
In the scripts
folder you'll see the following script:
const fs = require('fs')
require('dotenv').config()
if (process.env.NEXT_USE_SSR === '1') {
fs.copyFileSync(
'./src/templates/[[...slug]].ssr.tsx',
'./src/pages/[[...slug]].tsx'
)
} else {
fs.copyFileSync(
'./src/templates/[[...slug]].ssg.tsx',
'./src/pages/[[...slug]].tsx'
)
}
This will validate if you want to use regular SSR or SSG. Both are supported by Next.js. You only need to change the flag on the .env
file.
After the validation it'll copy a template
into the pages
folder.
import { GetServerSideProps } from 'next'
import Page, { PageProps } from '../components/Page/Page'
import { getPageBySlug } from '../libs/contentful'
export default Page
export const getServerSideProps: GetServerSideProps<PageProps> = async (
context
) => {
let slug = context.params?.slug || '/'
if (slug && typeof slug !== 'string') {
slug = `${slug.join('/')}`
}
const page = await getPageBySlug(slug)
return {
props: {
page: page.fields,
},
}
}
We're fetching the page by slug
from Contentful. After we fetch the entry we return the fields as a prop for our Page
component.
Our Page
component iterates over the components
property and finds the matching react component in our app.
import type { PageFields } from '../../types'
import ComponentMap from '../ComponentMap'
export interface PageProps {
page: PageFields
}
export default function Page({ page }: PageProps): JSX.Element {
return (
<>
{page.components?.map((component, index) => {
if (component.sys.contentType.sys.id) {
const Component = ComponentMap.get(component.sys.contentType.sys.id)
return <Component {...component.fields} key={index} />
}
})}
</>
)
}
Finally, the Hero component gets created thanks to our ComponentMap.ts
file. This will use the Content type ID hero
as a key and the Hero
component as a value.
import Hero from './Hero/Hero'
const ComponentMap = new Map()
ComponentMap.set('hero', Hero)
export default ComponentMap
Deploying to vercel
This starter kit is compatible with Vercel. You only need to set up the project and remember to put your Contentful API keys in.
Github repo and Lighthouse score
Feel free to check out the Github repo where you can find the source code of this project. This example provides the following Lighthouse score to get started. Pretty cool, isn't it?