Content Preview for your Contentful-Gatsby site with Next.js

Kevin Green
The Couch
Published in
5 min readJan 21, 2019
Someone drafting up some of that good good internet via startup stock photos

Contentful is a really powerful CMS that we use on a number of projects at The Couch. However despite most of our clients having an intimate hate for Wordpress, they do have an intimate love for some of the common features. One of which isn’t something that works out of the box with Contentful: Preview.

We build a number of our Contentful sites with Gatsby. Most of our sites have a build time anywhere between 30s to 4 minutes. Because of this wait we’ve implemented some work arounds that allow clients to preview content in the production build. This however has a wait time, as originally pointed out by Work and Co. We opted for another route that would allow for instant previews, and not require the client to publish articles before they were ready.

This was even more important for Supercluster. We built them a very modular article templates that allowed for a diverse editorial experience. We also created an image module that could be rendered in various unique ways on the screen. This required the client to essentially build/test the article and make sure images/text never overlapped depending on the content. We also used the Contentful Rich Text editor to inline modules and make the editing experience even smoother.

Enter Next.js

We needed a quick way to replicate the current production code in a preview environment. Since we were using Gatsby the frontend language was built in React. As a result we picked Next.js as the framework for rendering our dynamic previews.

Gotchas —

  • Next.js doesn’t do shared components from other projects very well
  • We’re using PostCSS in our Gatsby build so importing and compiling that in Next isn’t something supported out of the box
  • Because we’re copy and pasting the Gatsby build into Next.js we’ll also need to install all the dependencies in the Gatsby app (at least for the template we’re previewing)
  • We’ll want to run a server so we can serve a robots.txt disallow
  • Gatsby { Link } is trouble… more on that later

Fixing the shared components… I spent the better part of ~5 hours troubleshooting this, and eventually caved on a simpler solution that wouldn’t require things like symlinking/transpiling external modules with complex configurations. The solution? Copy your Gatsby directory into your next app before you build it so you can always access the most up-to-date shared components from the parent project.

Getting our styles out of Gatsby also proved relatively difficult. Getting PostCSS to work in Next.js is its own can of worms. As a result I opted to handle all the PostCSS work in the package.json file. Depending on the architecture of your project you may not run into this issue. I’ll share my package.json scripts for this project below regardless:

"scripts": {
"dev": "next",
"copy": "npm run build:css; rm -rf gatsby/; cp -R ../src gatsby",
"copy-fonts": "cp -R ../static static",
"build": "next build",
"build:css": "postcss gatsby/styles/main.css -o static/main.css",
"start": "next start"
},

Keep in mind, while developing you could run a prestart script as well, but you’ll not want that in the now production because it will run into trouble finding the parent directory!

Now we can finally build our preview page component. I’m going to show you the whole component and then explain what’s going on:

Those of you familiar with Next.js shouldn’t see anything that unusual here. We’re importing our article from our copied Gatsby template file. We’re also including the compiled CSS from our build task above in the header.

The only real work going on here is the query to get the article based on the id. We’re not including things like layout/header/footer modules as we don’t need them for the preview.

To get this hooked up you have 2 options, the first being ngrok for local development, and the second being a now deployment. Once you have an endpoint set up we’ll want to go into Contentful. Settings->Content Preview from there you can specify the content type you want to be able to preview, in this case Articles and set the url you’ll want to handle the preview.

e.g. http://site-preview.now.sh/preview?id={entry.sys.id}

Once that’s hooked up you should now be able to preview articles from Contentful to your local/deployed environment.

Additional Gotchas — Data Structure

There’s always something else right? So in my case I actually don’t use the gatsby-contentful-source plugin. I ran into a lot of problems with modular nested content and it would just continuously cause build fails depending on the initial article that was queried to build the schema. So I rolled my own source plugin for Contentful. This allowed me to fetch the Contentful data on my own, and as a result I simply handled the data in a large JSON response. This actually benefited me in the long run because the above app has the same data structure. If you end up using the default source plugin you will not be able to simply reference the article.js template like I have. This is because the GraphQL data structure is so different from the Contentful Preview API response.

Robots.txt

Because this is a preview server, we’ll want to add a robots.txt file, so the crawlers don’t ever index this content unnecessarily. Since we’re using Next.js this is pretty easy. We’ll have to set up a server.js file and populate it as follows:

You just need to create a robots.txt file in a directory within your app, in my case I made one in a folder called raw.

import { Link } from ‘gatsby’

If you’re using this in any of your components that you are previewing you’ll encounter errors. Gatsby Link mounts a static query that Next.js isn’t a big fan of. So we’re gonna use replace to update all the instances of Link in our components after we copy them over…

It’s just one final gotcha ;). If you have any other variations feel free to add them, and then just add another script to package.json like node replace.js.

Last Thoughts

The hardest part of this was importing the components and styles out of the Gatsby app into Next.js. I also tried to do this with react-create-app but that also doesn’t like importing from parent directories. If you have a larger organization you could potentially leverage npm link and host private repos for your shared components. I however didn’t want to add any additional levels of technical debt to this project, so I kept everything in the build process documented in the package.json.

Also choosing Next.js meant that we could quickly deploy to services like now and create alias now domains without needing to set up additional subdomains for the client.

Would love to hear how others are doing this, I know Gatsby recently released a preview functionality, but at ~300/month it’s a pretty steep sell.

~Cheers

--

--