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

Installing the prismic-cli command line tool.

prismic theme https://github.com/raulg/prismic-next-blog

Quickstarting your Prismic boilerplate project.

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 documents
  • package.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

Adding the prismic-javascript and prismic-reactjs dependencies to fetch and render documents.

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.

Note: In this case, you will be using a rich text field that will serve as the body of the post, for the sake of simplicity. Normally, the body of a document would be a group of Slices to allow more flexibility when creating your posts.

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

An example /pages/index.js file fetching the author data from blog_home.

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.

Note: If you run the app now with 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

An example /pages/index.js file that displays a list of all blog posts.

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

An example /pages/post.js file that generates pages depending on the UID provided by the context.

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 '/'
}

Helper functions in the prismic-configuration.js file.

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>
)

Modifying the /pages/index.js file to add the blog posts link list.

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')
}

Enabling SPR in your BlogHome.getInitialProps and Post.getInitialProps functions.

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.



Written By
Written by raulgraulg
on June 26th 2019