Manual Previews

How to set everything up to make Prismic previews work by doing a manual set up.


Previews with HOCs or Manual Previews, which one to choose?

If you've browsed the documents in this same section, you may have noticed that there are two ways of setting up previews in your project. The option you chose will depend on your needs:

  • Preview with HOCs: Choose this option for a quick and easy setup that doesn't require extra configuration. Use High Order Components to wrap your pages and templates and set up a global store to access the preview data.
  • Manual Preview: You can choose to add a manual setup if you need to customize how the preview data is stored. e.g., if you've set up Redux or such. This setup it's designed for more advanced use cases. It uses the underlying usePrismicPreview hook and mergePrismicPreviewData helper function.

Enable Previews in your repository

Start with setting up the previews in your Prismic repository, read the dedicated guide to learn how to do it, and then come back.

Enable previews in your project code

The gatsby-source-prismic plugin provides a way to load previews directly from Prismic. By rendering previews client-side, we can retain the benefits of Gatsby's HTML pre-rendering while still providing the dynamic and rich content editing experience of a traditional server setup.

Enable the Prismic Toolbar (optional)

You may optionally enable the Prismic Toolbar to use it when previewing Releases and using Sharable links with your team. You can enable this by setting the prismicToolbar option in your gatsby-config.js file to true.

Copy
plugins: [
  {
    resolve: 'gatsby-source-prismic',
    options: {
      repositoryName: 'your-repo-name',
      prismicToolbar: true
    }
  }
]

Create a preview page

Create a preview page inside your project in src/pages/prewiew.js.

preview.js

Prismic sends previews to an endpoint on your site along with data representing the preview. This endpoint can be set to any page, but /preview is the most common choice. The rest of this guide assumes the endpoint to be /preview, but you can replace this as needed.

Here we'll use the usePrismicPreview hook to fetch our preview data from Prismic. Provide your repositoryName to the hook. There are other optional values that you can pass to it: See the complete list here.

Then, We'll need to save the preview data globally to use it on the document's page. This could be a Redux store or a React Context value. For this example, we'll just use window.

Finally, at the end of the page, we're going to use navigate() to handle the case of an unpublished page. This will go to the /unpublishedPreview route which we'll create in the next step.

Copy
import React, { useEffect } from 'react'
import { navigate, useStaticQuery, graphql } from 'gatsby'
import { usePrismicPreview } from 'gatsby-source-prismic'

// Note that the `location` prop is taken and provided to the `usePrismicPreview` hook.
const PreviewPage = ({ location }) => {
  // Let's use a static query to retrieve all known paths. We'll use it later
  // to navigate to the unpublishedPreview page if the document is not
  // published.
  const { allSitePage } = useStaticQuery(graphql`
    {
      allSitePage {
        nodes {
          path
        }
      }
    }
  `)
  const allPaths = allSitePage.nodes.map((node) => node.path)

  const { isPreview, previewData, path } = usePrismicPreview({
    // The repositoryName value from your `gatsby-config.js`.
    repositoryName: 'your-repo-name',
  })

  // This useEffect runs when values from usePrismicPreview update. When
  // preview data is available, this will save the data globally and redirect to
  // the previewed document's page.
  useEffect(() => {
    // If this is not a preview, skip.
    //   null = Not yet determined if previewing.
    //   true = Preview is available.
    //   false = Preview is not available.
    if (isPreview === false || !previewData) return

    // Save the preview data to somewhere globally accessible. This could be
    // something like a global Redux store or React context.
    //
    // We'll just put it on window.
    window.__PRISMIC_PREVIEW_DATA__ = previewData

    // Navigate to the document's page if page exists.
    if (allPaths.includes(path)) {
      navigate(path)
    } else {
      navigate('/unpublishedPreview')
    }
  }, [isPreview, previewData, path])

  // Tell the user if this is not a preview.
  if (isPreview === false) return <div>Not a preview!</div>

  return <div>Loading preview...</div>
}

export default PreviewPage

⚠️ Update the repositoryName

Make sure that you update the repositoryName to match the URL of the Prismic repository created earlier in this article. To find this, go to your Prismic dashboard, then to your repository.

If the URL for your repository is https://my-awesome-repository.prismic.io, you'll need to replace 'your-repo-name' above with 'my-awesome-repository'.

Create a route for unpublished pages

Create an unpublished document route handler on src/pages/unpublishedPreview.js.

For this example, we have a page template at ../templates/page.js. Remember to adapt this page to match your project needs and perform any logic from previewData to determine the correct page or template component to use.

Copy
import React from 'react'
import { PageTemplate } from '../templates/page'

export const UnpublishedPage = (props) => {
  // const previewData = window.__PRISMIC_PREVIEW_DATA__
  return <PageTemplate {...props} />
}

export default UnpublishedPage

Add a helper to merge the preview data

On the page or template that our preview page will navigate to, we'll use the mergePrismicPreviewData helper function to merge the preview data with the existing static data recursively. The resulting object should match the static data with the new preview data. Let's create our helper in utils/usePreviewData.js.

Copy
import { useMemo } from 'react'
import { mergePrismicPreviewData } from 'gatsby-source-prismic'

// Returns true if we're in a browser, false otherwise. This will help guard
// against SSR issues when building the site.
const IS_BROWSER = typeof window !== 'undefined'

/**
 * Prismic preview hook
 * @param {object} staticData Data object from Gatsby page
 */
export default function usePreviewData(staticData) {
  return useMemo(() => {
    // If we're not in a browser (i.e. we're in SSR) or preview data has not been
    // set, use the non-preview static data.
    if (!IS_BROWSER || !window.__PRISMIC_PREVIEW_DATA__) return staticData

    return mergePrismicPreviewData({
      staticData,
      previewData: window.__PRISMIC_PREVIEW_DATA__,
    })
  }, [staticData])
}

Render the usePreviewData

The last step is to use the usePreviewData React hook to fetch preview data using Prismic's preview URL parameters on every page of your app. To do this we'll need to export the hook and then pass the result data to it, like so: const liveData = usePreviewData(data)

For our example, we're using the hook in the Page template in src/templates/page.js. Remember to pass it to every page of your site.

Copy
import React from 'react'
import { graphql } from 'gatsby'
import usePreviewData from '../utils/usePreviewData'

export const PageTemplate = ({ data }) => {
  const liveData = usePreviewData(data)

  return (
    <Layout>
      <h1>{liveData.prismicPage.data.title}</h1>
      <div
        dangerouslySetInnerHTML={{
          __html: liveData.prismicPage.data.body.html,
        }}
      />
    </Layout>
  )
}

export const query = graphql`
  query($id: String!) {
    prismicPage(id: { eq: $id }) {
      data {
        title
        body {
          html
        }
      }
    }
  }
`

Limitations

Shareable links

As for now, the shareable link functionality isn't fully unsupported when using Gatsby, you'll only be able to see the correct document by clicking the toolbar and clicking on the corresponding page you're trying to preview, otherwise, it will appear as a blank page. See the open issue in github.

Images

Using Imgix transformed images

If using Prismic's Imgix integration and the GatsbyPrismicImage... fragments for images, this works out of the box with previews. Default values are used for width/height, however, so be aware that your images may have different resolutions at preview time.

  • Fixed images: Defaults to 400px width.
  • Fluid images: Defaults to 800px max width.

Using locally transformed images

If you are using gatsby-transformer-sharp and the localFile field for images, we cannot perform the same image optimizations that we do at build-time. Instead, usePrismicPreview() returns just the URL field for an image.

In this case, We recommend creating a custom <Image /> React component that can conditionally render a normal <img /> when an src is specified, or fallback to gatsby-image data otherwise. Taking this approach will ensure that we utilize fresh preview data for images, but still retain the benefits of lazy-loaded images when statically viewing our site.

Below is a simple example of such a component:

Copy
import React from 'react'
import GatsbyImage from 'gatsby-image'

export const Image = ({ src, fixed, fluid, ...props }) =>
  src ? (
    <img src={src} {...props} />
  ) : (
    <GatsbyImage fluid={fluid} fixed={fixed} {...props} />
  )

Aliases

GraphQL aliases are not supported since previews do not have access to your Gatsby GraphQL query. This means that if you perform anything like this in your GraphQL queries:

Copy
query {
  prismicPage(uid: { eq: $uid }) {
    uid
    data {
      myAliasedTitle: title {
        text
      }
    }
  }
}

Previews will not function properly since previewData will not change title to myAliasedTitle.


Was this article helpful?
Not really
Yes, Thanks

Can't find what you're looking for? Get in touch with us on our Community Forum.