Create and Deploy a Next.js and Prismic App with ZEIT Now
Create a Next.js and Prismic app that is deployed with ZEIT Now.
In this guide, you will create a Next.js blog site from scratch that will show you how to; source the content you have in a Prismic repository, create pages programmatically, handle dynamic routing, and deploy it with Now.
Next.js from ZEIT is a production-ready framework that helps you create fast React apps. Prismic is a Headless Content Management System that helps developers and content managers to work on websites and apps together.
Step 1: Set Up Your Prismic + Next.js App
For this guide, you will start with installing a boilerplate Next.js project that uses Prismic. Start with installing the Prismic CLI package, followed by quick-starting your project from the provided git repo.
This process clones the codebase and guides you through setting up the repository that will be used as your blog's content source.
npm i -g prismic-cli
prismic theme https://github.com/raulg/prismic-next-blog
Navigate to the folder you have created and inspect the files and folders that are included in this barebones project. You will find the following:
/custom_types
, which details the data modeling for your Prismic repository, in this case the blog_home and post documentspackage.json
, which includes the Next.js and React dependencies, as well as scripts to develop and deploy for Now
You can run your app with the npm run dev
command, and check at localhost:3000
that the app is running correctly.
You will notice that for now it is only a simple index page, as defined in /pages
. This takes care of getting your simple Next.js app started, you can now begin setting up your Prismic repository.
Continue by installing the required packages to integrate your Next.js web app with Prismic.
npm i prismic-javascript prismic-reactjs
If you open the prismic-configuration.js
file, you might notice that the API endpoint has already been set up according to the repository you created during the installation process.
Confirm the name of the repository so you can access the Prismic dashboard to manage your content. Move into the Prismic repository that you started earlier, and create some content that you will use in your project.
Just a simple blog home page and a couple of posts will do for now, but you can get as creative as you wish to.
Step 2: Sourcing Your Content From Prismic
With the relevant Prismic dependencies installed, you can start building a page that will serve as a blog index. /pages/index.js
will have a component that will get the blog_home document with getInitialProps
and render it's Rich Text fields.
import React from 'react' import Prismic from 'prismic-javascript' import { RichText, Date } from 'prismic-reactjs' import { client } from '../prismic-configuration' const BlogHome = props => ( <div> <img src={props.home.data.image.url} alt="avatar image" /> <h1>{RichText.asText(props.home.data.headline)}</h1> <p>{RichText.asText(props.home.data.description)}</p> </div> ) BlogHome.getInitialProps = async context => { const home = await client.getSingle('blog_home') return { home } } export default BlogHome
The home
prop now contains the document object received from the API, including the data fields you set earlier for the blog author's image, title, and short description.
npm run dev
, you will see this information displayed at localhost:3000
.There are many ways to query the API to get the data you require. For now, use a Predicate to get all the post documents you have created and sort them in descending order based on their assigned date.
const BlogHome = props => ( <div> <img src={props.home.data.image.url} alt="avatar image" /> <h1>{RichText.asText(props.home.data.headline)}</h1> <p>{RichText.asText(props.home.data.description)}</p> <ul> {props.posts.results.map(post => ( <li key={post.uid}>{RichText.render(post.data.title)}</li> ))} </ul> </div> ) BlogHome.getInitialProps = async context => { const home = await client.getSingle('blog_home') const posts = await client.query( Prismic.Predicates.at('document.type', 'post'), { orderings: '[my.post.date desc]' } ) return { home, posts } } export default BlogHome
The posts
prop contains an array of all the blog posts in your repository, arranged in descending chronological order. The title field of each item is rendered in an unordered list.
That's it for a minimalist blog home page. Let's move on to rendering the pages for each of your blog posts.
Step 3: Rendering Dynamic Posts
To create a page for each blog post document, you will set it up so that the page is generated dynamically using the unique individual slug (UID) that identifies each post document.
This approach is very similar to that used with the home page, but the API query in getInitialProps
will instead fetch the document depending on its UID.
import React from 'react' import { RichText, Date } from 'prismic-reactjs' import { client } from '../prismic-configuration' import Link from 'next/link' const Post = props => ( <div> <Link href="/"> <a>back to blog list</a> </Link> {RichText.render(props.post.data.title)} <span>{Date(props.post.data.date).toString()}</span> {RichText.render(props.post.data.post_body)} </div> ) Post.getInitialProps = async context => { const { uid } = context.query const post = await client.getByUID('post', uid) return { post } } export default Post
Step 4: Build Client Side Navigation Links
Now that the pages for your blog post documents are accessible, you can modify the index page so that the list of titles actually links to each of the posts. To do this, it's best to use the <Link>
component, included with Next.js, to provide client-side navigation without a page refresh.
The <Link>
component requires two main props for navigation: href
, which will be the path used to route to the page, and as
, which will be the path as rendered in the browser. To aid in creating these two different paths, you can use the linkResolver
and hrefResolver
helper functions, defined within prismic-configuration.js
.
// Manages links to internal Prismic documents linkResolver: function (doc) { if (doc.type === 'post') { return `/blog/${doc.uid}` } return '/' }, // Additional helper function for Next/Link components hrefResolver: function (doc) { if (doc.type === 'post') { return `/post?uid=${doc.uid}` } return '/' }
These helper functions generate both the aesthetic path with linkResolver
; and the functional path that will correctly pass the UID with hrefResolver
.
You can adjust the unordered list in /pages/index.js
so that it wraps a <Link>
around the title, as well as adding the Date
value for each of the blog posts.
+ import { client, linkResolver, hrefResolver } from '../prismic-configuration' + import Link from 'next/link' const BlogHome = (props) => ( <div> <img src={props.home.data.image.url} alt='avatar image' /> <h1>{RichText.asText(props.home.data.headline)}</h1> <p>{RichText.asText(props.home.data.description)}</p> <ul> {props.posts.results.map((post) => ( <li key={post.uid}> - {RichText.render(post.data.title)} + <Link href={hrefResolver(post)} as={linkResolver(post)} passHref prefetch> + <a>{RichText.render(post.data.title)}</a> + </Link> + <span>{Date(post.data.date).toString()}</span> </li> ))} </ul> </div> )
You can now refresh your site at localhost:3000
and test out the navigation for your blog. It's quite minimalistic, but you've built it from scratch.
Step 5: Deploying With Now
So far, you have been using npm run dev
to develop locally, but what good is a blog if you don't show it off to the world. It's time to deploy it to the Now platform and enjoy your serverless web app.
You can run npm run deploy
to launch the Now CLI which will quickly setup and deploy your project online. Once it's done, you can check the generated url.
Your minimalistic blog using Prismic and built with Next.js is now online on Now and can be shared instantly using the URL given by the Now CLI.
Bonus: Serverless Pre-Rendering
For increased performance, you can take advantage of the Serverless Pre-rendering feature to serve your dynamic content with static speeds.
All you need to do is add a couple of lines to your index.js
and post.js
files in the getInitialProps
method.
if (context.res) { context.res.setHeader('Cache-Control', 's-maxage=1, stale-while-revalidate') }
Deploy this new version to Now with npm run deploy
. You minimal blog is now being served even faster thanks to the Now Smart CDN. You can try adding or modifying content in your Prismic repository and it will be served instantaneously on your now public site.