Dynamic static sites - Implementing an oxymoron
You just write some GraphQL, pass the data to your UI components, and the rest is done for you.
"What if we took a static site, and made it more dynamic?" — Stephan
I laughed at first, shook my head, but then started thinking. What first seemed like a silly contradiction slowly started to make sense to me.
GatsbyJS offers a full-fledged static content authoring experience that allows connection of your projects to many APIs and data sources, including Contentful’s content infrastructure, making it an excellent companion to Gatsby. With Contentful being a first-class citizen in the Gatsby world, content is easily edited in a nice UI and with the use of Netlify, setting deployments up takes less than a minute.
The only benefit classic dynamic websites offer over these new workflows is that content can be edited right on the page — you click ‘edit’, make your changes, and you are done.
Thus, we set out to try and solve this using the Contentful delivery and especially the powerful management APIs, some GraphQL and a few terribly styled React components.
If you are curious about static sites, Gatsby, Gatsby plugin development or new ideas on how to use Content Infrastructure, then this post is for you.
There is a template with source files available on Github; this will come in handy as reference in later parts of this article.
Part I: Hitting the ground running
What we’re going to do first is set up a static site that is automatically deployed to Netlify. Let’s begin by using a starting template. Go ahead and click "Fork" in the upper right corner of the repo to make your own copy to work on.
After that, clone the project.
cd
into the directory and run npm install
While npm
is doing its thing, use the time to sign up for a free Contentful account — you can make it even easier and sign in using your Github account with one click.
Once you’re in, choose to create an empty space.
Now in the gatsby-starter-gcn
folder, run npm run setup
and follow the instructions.
It will bootstrap all the data that is needed for the example to run using the Contentful Import tooling, which in turn uses the Management API, the same thing we will be using later to actually update the content using our plugin.
After that is done, you can run npm run dev
and go to http://localhost:8000 to see your fresh new static site.
Next follow these deployment instructions, and optionally some additional settings, to get your website fully set up and accessible on the Internet. Now, every time you push some code or edit content, your site is automatically rebuilt.
Part II: The Gatsby Plugin
To recap our initial plan: We want to allow developers to easily mark parts of the static site as loaded from a specific Contentful entity and then show an ‘Edit’ link on the generated site. That allows any admin user with a Management Token to edit the content right on the website; with the updated content automatically showing up on the site after a while.
If you’ve followed Part I, that last part would already be taken care of — whenever you push code or publish an entity on Contentful, Netlify will rebuild your site and distribute it on its content delivery network (CDN).
Before we dive into the implementation details, let’s do a quick refresher on how Gatsby renders static sites:
In Gatsby, you define a ‘Page’ type and the GraphQL query, for all the data needed to render a page inline with the ‘Page’ component.
During the build stage, before rendering the component, that data is fetched from a ‘Source’ and then later provided to the component for rendering.
Contentful provides a source plugin for that out-of-the-box.
Gatsby also provides an extension API that allows you to hook into almost every step of the build process and customize things.
Let’s take a look at src/pages/index.js
: The query requests allContentfulPost
, yielding a list of all entries for the Post
content type. From there, it selects a set of properties that it needs to render.
In order to build an editing component, in addition to the actual content, we need to know the associated content model in Contentful so that we can render an interface to edit the content.
Here’s the query we’d like to use:
This little addition tells the internal GraphQL endpoint that we would like to have a contentfulEditor
object that contains the Content Type ID, Entity ID, Space ID, and the id and type of all the fields.
"That’s great, Tim, but so far that’s nothing but wishful thinking", I hear you say.
That is true, but having specified our interface now, it will be much easier to know exactly what we need to implement. So let’s jump to that.
The Plugin
As mentioned earlier, Gatsby allows you to hook into almost every build step. What we would like to do is hook into a point where the data has already been loaded, then add some additional data about the content model on top of it.
The ‘setFieldsOnGraphQLNodeType’ extension point is the perfect candidate for that. It allows you to change the data from the GraphQL query, before any pages were rendered, but after the Contentful source plugin has already fetched the data.
First, we create a folder ‘plugins’ in the project root — Gatsby will automatically look through any folders in the ‘plugins’ directory, so let’s create a folder named ‘contentful-editor’ inside of that.
Within ‘contentful-editor’, create a package.json
file containing just ‘{}’ (Gatsby infers the plugin name from the folder structure) and a gatsby-node.js
file. That tells Gatsby to register an extension to run for every node
; meaning it will be called for every Page that you are about to define.
In there, we will want to do the following:
If a node contains data fetched from Contentful, collect all the entities in it and query the API for them
Query the Contentful API for all the Content Types that are associated with those entity
Append the previously defined data to every data node
Here’s what it will look like:
You can find the complete code in the gatsby-node.js file on Github.
The editor component
Now, we have all the data available, we can move on to rendering an inline editor.
Let’s once again do a quick recap on what we’ve done so far:
Set up your own gatsby example project on Github
Your example project is automatically deployed to netlify on any content changes or code changes
When rendering a page, we can now query for the metadata about the underlying content model for a page
What’s left to do:
We need to build a React component that can wrap any other React components that use data from Contentful
Let’s take another look at ‘src/pages/index.js’ (also available as reference on Github): The CardList
component iterates over all the posts from Contentful and renders a Card
component from every Contentful ‘Post’.
This is the ideal point where we can introduce our wrapper component that enables on-page editing. We wrap it with a ‘ContentfulEditor’ component and pass the ID, ‘contentfulEditor’ data and the post content to it:
Then, we proceed with creating a new file /src/components/ContentfulEditor.js
In there, we want to wrap the ‘Card’ so an ‘Edit’ button is shown on top of it. When that is clicked, a modal that renders an interface to edit content opens; that syncs any changes back to Contentful via the API. That in turn triggers a rebuild on Netlify, updating the actual site after a while.
When we click on the edit button, we open a modal with the editor. Inside of the editor, we extract the field data and, based on the type of a field, render an editor. This is done by the following code:
When ‘save’ is clicked, the following code uses the management SDK to upload the data to Contentful:
Now, just push your changes to Github, wait for Netlify to finish with the new build and you’re ready to go.
Conclusion
Contrary to popular belief, static sites actually can be made dynamic by using Contentful’s Content Management API’s — that’s a major benefit of using a Content Infrastructure over a traditional CMS. Imagine implementing a chatbot that allows you to update your static site via a simple chat message, or the ability to integrate your website with Amazon Alexa and update it with just voice interfaces — your imagination is the only limit as to where and how you can interact with your content.
Want to do more with Gatsby and Contentful? Get started here.