Disclaimer A new version of this tutorial has been released on February 03rd, 2020, and updated on November 09th, 2020, just right here: Build a static blog with Gatsby and Strapi
Our community is looking for talented writers who are passionate about our ecosystem (Jamstack, Open-source, JavaScript) and willing to share their knowledge/experiences through our Write for the community program.
A static website contains Web pages with fixed content. Technically, it is a simple list of HTML files, which displays the same information to every visitor. Unlike dynamic websites, they do not require any back-end programming or database. Publishing a static website is easy: the files are uploaded on a simple Web server or storage provider. The two main advantages of static websites are security and speed: there is no database so it can not be hacked and there is no need to render a page for each request, which makes Web browsing faster.
To make their creation easier, numerous open-source static websites generators are available: Jekyll, Hugo, Hexo, etc. Most of the time, the content is managed through static (ideally Markdown) files or a Content API. Then, the generator requests the content, injects it in templates defined by the developer and generates a bunch of HTML files.
Progressive Web Apps (PWA) are web applications, highly based on JavaScript, and are reliable, fast and engaging. Since they make web browsing much faster and offer a better user experience, PWA has become the default way to build Web interfaces. Thus, many amazing front-end frameworks appeared over the last couple years: Angular, React and more recently, Vue.
Gatsby: when static websites meet Progressive Web Apps
Both static websites and PWAs have strong advantages which make us crave for a way to use them together in the same project! Luckily, we have tools that bridge the gap between them and the one we recently heard of is definitely Gatsby. So, we decided to give you a complete example of how to get started with Gatsby. A static website needs a source of content: in this example, we will deliver it using an API built with Strapi.
What is Gatsby?
Gatsby is a blazing-fast website framework for React. It allows developers to build React based websites within minutes. Whether you want to develop a blog or a corporate website, Gatsby will fill your needs.
Because it is based on React, the website pages are never reloaded which makes the generated website super fast. A large set of plugins is available to allowing developers to save time coding. For example, plugins exist to get data from any source (Markdown files, CMS, etc.). Gatsby is strongly based on the "node" interface, which is the center of Gatsby's data system.
Created by Kyle Mathews, the project was officially released in July 2017. (As of February 2109,Gatsby is in Gatsby v2 and is now used by many companies and for hundreds of websites.
What is Strapi?
Strapi is an *open source Headless CMS Front-End Developers Love*. It's more than a Node.js Framework and more than a Headless CMS, it saves weeks of API development time, and allows easy long-term content management through a beautiful administration panel anyone can use.
Thanks to its extensible plugin system, it provides a large set of built-in features: Admin Panel, Authentication & Permissions management, Content Management, API Generator, etc.
Unlike other CMSs, Strapi is 100% open-source, which means:
- Strapi is completely free.
- You can host it on your own servers, so you own the data.
- It is entirely customisable and extensible, thanks to the plugin system.
Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series
Please follow along watching the videos below and reading the text. You can watch just the videos or read just the text, but you will get the most from this tutorial by watching and reading both. The videos are designed to be used together with this article.
The videos follow the exact sequence of this article. The videos contain additional information and additional configuration details for a few sections. However, for intermediate to advanced users this article will be sufficient to get oriented and started building Strapi powered Gatsby projects.
Index of Tutorial
DISCLAIMER: Are you sure to continue? A new version of this tutorial has been released in February 03 2020 and updated on November 09 2020 just right here: Build a static blog with Gatsby and Strapi
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Introduction
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Installation 2A. Learn Gatsby's with Strapi Headless CMS Video Tutorial Series - Administrators and Users
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Content Types
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Roles and Permissions
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Setting up Gatsby
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Create the Index page view
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Create the Article page view
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Gatsby Images & the Article page view 8B. Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Specify Node Version
- Learn Gatsbyjs with Strapi Headless CMS Video Tutorial Series - Deploy Strapi to Heroku 9A. Learn GatsbyJS with Strapi Headless CMS Tutorial Series - Configure again Permissions
- Learn GatsbyJS with Strapi Headless CMS Tutorial Series - Set-up Cloudinary & Netlify Predeploy
- Learn GatsbyJS with Strapi Headless CMS Tutorial Series - Deploy Gatsby to Netlify
- Learn GatsbyJS with Strapi Headless CMS Tutorial Series - Webhooks with Gatsby & Strapi
- Learn GatsbyJS with Strapi Headless CMS Tutorial Series - Adding Markdown Support
Note: Final tutorial and code is available at the GitHub repo for the Strapi and Gatsby tutorial. In this repo, you can download and/or copy/paste the example content.
Note: Within the content below we provide links that open a running localhost project. For either Strapi or Gatsby. These will not work if your server(s) have not been started.
1. Introduction
This video series will take you step by step through creating a blog in Gatsby and teach you how to connect it to the open sourced headless CMS - Strapi
Important links from Video:
2. Installation
Important links from Video:
Strapi CMS Setup
To make the magic happen, let's create a Strapi headless CMS and add some content.
Create a Strapi project
Let's get started!
Generate a Strapi project
Create a directory named tutorial
:
1mkdir tutorial
Navigate into tutorial
and then, using a single command, set-up and start your project inside your tutorial
folder:
1cd tutorial
2
3# Create a project using yarn
4yarn create strapi-app cms --quickstart
5
6# Create a project using npx
7npx create-strapi-app cms --quickstart
From /cms
, launch the Strapi server:
1yarn develop
2
3// or
4
5npm run develop
Using the --quickstart
flag creates a full Strapi project and automatically starts the server and opens up a tab in your browser.
(If you leave off --quickstart
, Strapi allows you to configure the project according to your needs, Strapi will ask you some questions about your preferences. In this case, reply to each of them or press enter to keep the default values. If you choose a different database than SQLite, you will need to separately install that database onto your system and have it running in the background.)
Additional information can be found in the Strapi documentation.
Create your first Administrator
Add your first Administrator using the registration page. This will be an Administrator role.
Restarting Strapi
After installation, and initial use, you will often close your project and work on other things, reboot your computer, etc. Therefore, you will need to restart Strapi and your project.
Enter inside your project folder, on the command line, (in this case tutorial/
, :
1cd cms
From cms/
, launch the Strapi server:
1strapi develop
2
3// or
4
5npm run develop
Starting here, you should be able to visit the admin panel of your project: http://localhost:1337/admin. You will now be directed to a login screen. Login using your Administrator role.
2A. Administrators and Users
Administrators and Users are separate roles.
- An "Administrator" has access and rights to the backend of Strapi. They have the ability to add content, add plugins, upload images, etc...
- A "User" is someone who interacts with your project through the front-end. Someone who makes a purchase, has an account, leaves a review, a comment, etc.
At this point, you have created an Administrator, now you will need to create a User.
Click on Users located under CONTENT TYPES in the left-hand menu.
- Click the blue + Add New User button in the top right corner.
- Next, complete the
Username
,Email
, andPassword
fields. - Select
ON
for the Confirmed toggle field. - To the right, under Role, select
Authenticated
.
3. Content Types
Important links from Video:
Create a Content Type
Strapi CMS projects are based on a data structure called Content Types (equivalent to models in frameworks and Content Types in Wordpress).
Create a Content Type named article
with four fields:
title
(typetext
and then selectshort text
)content
(typeRich Text
)image
(typemedia
then selectSingle Media
)author
(typerelation
, many articles to one user)
After creating your fields, as above, save your new content type and wait for Strapi to restart.
Insert some entries
Add some articles in the database. To do so, follow these instructions:
- Visit the articles list page.
- Click on
Add New Article
. - Insert values, link to an author and submit the form.
- Create two other articles.
Note: You can download the sample content from the video here.
4. Roles and Permissions
Allow access to Article
For security reasons, API access is, by default, restricted. To allow access, visit the Settings then Roles & Permissions click on Public
, select the Article - find
action and save. At this point, you should be able to request the list of articles.
Static website development
Great job, our API is ready! We can start developing the static website.
5. Setting up Gatsby
Important links from Video:
Install Gatsby
First, install Gatsby CLI:
1npm install --global gatsby-cli
Generate a Gatsby project
In the folder tutorial
that you previously created, generate your brand new blog:
1gatsby new blog
Start in development mode
Enter in your project's folder:
1cd blog
Start the server:
1gatsby develop
At this point, you should already be able to get access to your Gatsby website at this address: http://localhost:8000.
Install the Strapi source plugin
When you manage a static website, your data can come from different sources: Markdown files, CSV files, a WordPress website (using the JSON REST API plugin), etc.
Gatsby understands this pretty well. So its creators decided to build a specific and independent layer: the data layer. This entire system is strongly powered by GraphQL.
To connect Gatsby to a new source of data, you have to develop a new source plugin. Fortunately, several source plugins already exist, so one of them should fill your needs.
In this example, we are using Strapi. Obviously, we are going to need a source plugin for Strapi APIs. Good news: we built it for you!
Let's install it:
Path: blog/
1#using yarn
2yarn add gatsby-source-strapi
3
4#using npm
5npm install --save gatsby-source-strapi
This plugin needs to be configured. Replace the content of gatsby-config.js
with:
NOTE: Please understand that the apiURL:
, e.g. http://localhost:1337
does NOT have a trailing slash. This will create issues, as a slash is added by other code in the plugin.
Path: blog/gatsby-config.js
Allow access to User
Remember, when we created the content type we created a relation between User and Articles.
Like Article
,User
, link is likewise, by default, restricted. But Gatsby needs access, so to allow access, visit the Auth and Permissions section for Public role, click on Public
, select the User - find
action and save. After saving; Gatsby will have access to all the necessary content types managed by Strapi (for this tutorial).
Restart Strapi from the command line, inside the cms
folder - first by Ctrl
+ C
to stop the server; and then typing strapi develop
, to restart it.
Next, restart the Strapi server to allow Gatsby to register these updates, the next time you restart Gatsby.
Optional: Modify the <Layout />
component. Add Strapi to the footer.
Replace the following <footer>
section.
Path: blog/src/components/layout.js
1<footer>
2 © {new Date().getFullYear()}, Built with
3 {` `}
4 <a href="https://www.gatsbyjs.org">Gatsby</a> and {" "}
5 <a href="http://strapi.io">Strapi</a>
6</footer>
6. Create our Index Page
Important links from Video:
Articles list
First, we want to display the list of articles. To do so, add the following content in the existing home page file:
Path: blog/src/pages/index.js
What are we doing here?
At the end of the file, we export pageQuery
, a GraphQL query which requests the entire list of articles. As you can see, we require only the id
, title
and content
fields, thanks to the precise GraphQL query language.
Then, we pass the { data }
destructured object as parameter of IndexPage
and loop on its allStrapiArticle
object to display the data.
Tip: generate your GraphQL query in seconds!
Gatsby includes a useful GraphiQL interface. It makes GraphQL queries development way easier and intuitive. Take look at it and try to create some queries.
Adding images
To add images, we will need to import Img
from package gatsby-image
installed by default. Replace the content of blog/src/pages/index.js
with the following :
Path: blog/src/pages/index.js
7. Create the Article page view
Important links from Video:
Article view
Our website now starts looking like a blog which is a good thing. However, an important part is still missing: the article’s details page.
Let's create the template, containing a specific GraphQL request and defining the content displayed:
In order to do this, first create a folder called templates
in your src
directory. Then within templates
create a file called article.js
.
Path: blog/src/templates/article.js
That looks fine, but at this point, Gatsby does not know when this template should be displayed. Each article needs a specific URL. So, we are going to inform Gatsby about the new URLs we need thanks to the createPage
function.
First, we are going to code a new function called makeRequest
to execute the GraphQL request. Then, we export a function named createPages
in which we get the list of articles and create a page for each of them. Here is the result:
Path: blog/gatsby-node.js
Restart the Gatsby server.
From now on, you should be able to visit the detail page by clicking on URLs displayed on the homepage.
8. Gatsby Images and author page
Important links from Video:
Fluid Images
Note: In the video, the maxWidth
attribute of the image (in the graphql variable) was set to 500
. However, this should have been set to 960
, which matches the max-width
of the enclosing container div.
Give your header image a fluid/responsive image.
Path: blog/src/templates/article.js
A. Edit the query variable export to match:
1export const query = graphql`
2 query ArticleTemplate($id: String!) {
3 strapiArticle(id: { eq: $id }) {
4 title
5 content
6 image {
7 childImageSharp {
8 fluid(maxWidth: 960) {
9 ...GatsbyImageSharpFluid
10 }
11 }
12 }
13 author {
14 id
15 username
16 }
17 }
18 }
19`
B. Edit the <Img />
component tag as follows:
1<Img fluid={data.strapiArticle.image.childImageSharp.fluid} />
Author view
Articles are written by authors. They deserve a dedicated page.
The processes for creating author views and article pages are very similar. First, create a new file in our templates
folder called, author.js
. Add the code below to this file.
Path: blog/src/templates/author.js
Second, we update the gatsby-node.js
file to create the URLs (with the below code):
Path: blog/gatsby-node.js
Finally, restart the server and visit the author page from the article view's links.
8B. Specify Node Version
Important links from Video:
On April 23, 2019 Node v12.0.0 was released. There is an incompatibility or bug that is present regarding SQLite.
Therefore, make the following change to your package.json
file found in your Strapi project root:
Path: cms/package.json
Change the engines
object from:
1 "engines": {
2 "node": ">= 10.0.0",
3 "npm": ">= 6.0.0"
4 },
To:
1 "engines": {
2 "node": "10.x",
3 "npm": ">= 6.0.0"
4 },
After changing your file and saving it, you may simply continue to the next section.
9. Deploy to Heroku
Important links from Video:
- Create Free Account with Heroku
- Strapi Documentation - Deploying to Heroku
- Heroku Postgress Add-on
- Heroku CLI Docmentation
We will deploy Strapi to Heroku. You will need a free account with Heroku.
Next install the Heroku CLI.
These commands are to login to Heroku and to create a new Strapi Project.
Path: ./
1heroku login
Edit .gitignore file
Open your editor and add package-lock.json
to the .gitignore
file.
Path: cms/.gitignore
1############################
2# Strapi Heroku
3############################
4
5package-lock.json
Next, you will need to init Git and commit your project
1cd cms
2git init
3git add .
4git commit -m "Initial Commit"
Create a Heroku Project.
1heroku create
You NEED TO set-up a database to work with Strapi. Here are step-by-step instructions to set-up a PostgreSQL or a MongoDB database. Follow the steps in the links, and then continue below.
Lastly, commit, push to heroku, and open your project.
1git commit -am "Update database config"
2git push heroku master
3heroku open
If your browser window opens at the Heroku URL, congratulations. If not, please review the documentation and the video for additional details.
Set-up Administrator and User Roles
Your browser should have opened back up to the Strapi Welcome page. Click on the /admin
link to enter the Administrator User
.
- Complete the form for the first
Administrator User
. - Click on Users located under CONTENT TYPES in the left-hand menu.
- Click the blue + Add New User button in the top right corner.
- Next, complete the
Username
,Email
, andPassword
fields. - Select
ON
for the Confirmed toggle field. - To the right, under Role, select
Authenticated
.
Insert some entries
Articles now need to be added again to the Production
installation of Strapi. Add some articles in the database. To do so, follow these instructions:
- From your dashboard, click on the
Articles
content type in the left-hand menu. - Click on
Add New Article
. - Insert values, link to an author, and submit the form.
- Create two other articles.
Note: You can download the sample content from the video here.
9A. Configure again Permissions
You have to allow access through the API under Settings then Roles & Permission from your Strapi Dashboard.
You have already set these permissions on your local Dev environment. But these settings need to be set again for Heroku as these settings are saved to a database and the Heroku PostgreSQL database is different than your local Dev environment.
- Login to your Strapi Dashboard, from
https://your-heroku-url.herokuapp.com/admin
. - Go to Settings then Roles and Permission and then click on
Public
. Set yourArticle
permissions sofind
andfindone
are checked.
- Within Settings then Roles and Permissions and
Public
, scroll to and click onUSERS-PERMISSIONS
, and setUser
permissionsfind
to checked.
- Save these changes
You have now allowed access through the API to Articles
, Article
and Users
.
10. Set-up Cloudinary & Netlify Predeploy
Important links from Video:
DEMO Urls:
API demos:
At this point, when you upload images to Strapi on Heroku, the images are not permanently saved. The reason is that they are saved to a temporary cache which gets deleted whenever Heroku goes to sleep.
Therefore, you will want to use a 3rd party service to upload to and then serve your images from. This tutorial continues with Cloudinary.
- First, create a Free Account with Cloudinary
- Use NPM to install the Strapi Cloudinary plugin, from your command line:
Next, install the plugin with npm, commit and push your changes to Heroku:
Path: ./cms
1npm i --save strapi-provider-upload-cloudinary
2git add .
3git commit -m "Installed Cloudinary Plugin"
4git push heroku master
Wait for Heroku to install the packages and to restart the server instance.
From your Cloudinary console, you will find your Cloudinary credentials to enter in Strapi:
From the Strapi Dashboard, click on Plugins
and then for FILES UPLOAD
click the cog
icon.
Select Cloudinary
in the Providers
dropdown and enter in your credentials:
- Cloud name
- API Key
- API Secret
Then save your changes in the Upload - Settings
.
Delete from Files Upload
the references to previously uploaded images.
Now, for each content-type containing images, upload again the images that correspond to your existing content:
From now on, new content will automatically have their images saved and served from Cloudinary.
11. Deploy Gatsby to Netlify
Important links from Video:
- Create Free Account with Netlify
- Netlify CLI Documentation
- Video Demo URL
- This Video Tutorial GitHub DEMO
- Long-term Netlify Demo
- Long-term Netlify Demo GitHub
You are going to need to prepare a few things:
- Sign-up for a Free Account with Netlify
- Create a new GitHub Repo where your Gatsby site will live and be updated from.
Next, the Gatsby part of your project needs to be pushed to your new GitHub repo:
Path: ./blog/
1git init
2git add .
3git commit -m "first commit"
4git remote add origin git@github.com:YOUR-NAME/YOUR-NEW-EMPTY-REPO.git
5git push -u origin master
After setting up your Gatsby site on GitHub for deployment to Netlify, we need to edit the gatsby-config.js
.
Locate gatsby-source-strapi
plugin object and replace it with the following code:
Path: ./blog/gatsby-config.js
1 {
2 resolve: `gatsby-source-strapi`,
3 options: {
4 apiURL: process.env.DEPLOY_URL
5 ? "https://YOUR-APP-URL.herokuapp.com"
6 : "http://localhost:1337",
7 contentTypes: [`article`, `user`],
8 queryLimit: 1000,
9 },
10 },
Open your .gitignore
file and add package-lock.json
to the ignore list.
Path: ./.gitignore
1...
2
3# Yarn
4yarn-error.log
5.pnp/
6.pnp.js
7# Yarn Integrity file
8.yarn-integrity
9
10package-lock.json
Next, you need to git add
, git commit
and git push
your new changes. From your command line:
Path: ./blog/
1git add .
2git commit -m "Update config-gatsby.js and .gitignore file"
3git push
In order to easily push your Gatsby site to Netlify, you have to install and login to Netlify using the Netlify CLI
:
From your command line:
1npm install netlify-cli -g
2netlify login
Press the Authorize
button and close the tab or window.
Netlify is now set-up on your computer. It's time to initialize your project (Please pay close attention to the build command
and directory
):
Path: ./blog/
1netlify init
2? What would you like to do? + Create & configure a new site
3? Site name (optional):
4? Team: YOUR NAME HERE
5
6Site Created
7
8Admin url: https://app.netlify.com/sites/SITE-NAME
9Site url: https://SITE-NAME.netlify.com
10Site ID: YOUR-UNIQUE-SITE-ID
11
12? Your build command (hugo/yarn run build/etc): gatsby build
13? Directory to deploy (blank for current dir): public
14? No netlify.toml detected. Would you like to create one with these build settings? Yes
15
16Creating Netlify Github Notification Hooks...
17Netlify Notification Hooks configured!
18
19Netlify CI/CD Configured!
20
21The site is now configured to automatically deploy from GitHub branches & pull requests
22
23Next steps:
24
25 git push Push to your git repository to trigger new site builds
26 netlify open Open the Netlify admin URL of your site
A last git add
, git commit
and git push
are needed in order to finish the connection between your GitHub and Netlify. Then open your Netlify Deployment Console
.
From your command line:
Path: ./blog/
1git add .
2git commit -m "netlify config settings files"
3git push
4netlify open
After Netlify finishes deploying your site, you can click the green site link to see it.
12. Webhooks with Gatsby & Strapi
Important links from Video:
- Final Netlify Demo URL
- Final Heroku Demo URL
- Netlify Webhooks Doc
- Strapi Webhooks Doc
- GitHub for Netlify hosted Demo
Create and Copy a Netlify WebHook URL
- Login into your Netlify Login
- From your App, go to: Settings -> Build & deploy -> Continuous deployment -> Build hooks
- Click
Add build hook
- Give your app a
build hook name
, e.g.strapiUpdate
- Save it and then copy the issued URL to the clipboard.
Add a Variable to your custom.json
file
You will need to create a variable for the webhook. We will use this variable to update any content-type and their models. If the webhook changes, you will only need to change this variable.
Path: ./cms/config/environments/production/custom.json
Add the following line:
1 "staticWebsiteBuildURL": "https://api.netlify.com/build_hooks/5cc30b_YOUR_CUSTOM_URL_2a83"
And it should look like this after:
1{
2 "myCustomConfiguration": "This configuration is accessible through strapi.config.environments.production.myCustomConfiguration",
3 "staticWebsiteBuildURL": "https://api.netlify.com/build_hooks/5cc30b_YOUR_CUSTOM_URL_2a83"
4}
Modify the model for the Article
Content Type
The following is the new Article.js
file. This file now has additional code that use the variable with the Netlify webhook. Whenever this Content-Type is creating a new instance, updates one or deletes one of the content types, it will fire a Post
request to Netlify using the Webhook URL.
Path: ./cms/api/article/models/Article.js
1'use strict';
2
3const axios = require('axios');
4
5/**
6 * Lifecycle callbacks for the `Article` model.
7 */
8
9module.exports = {
10 // Before saving a value.
11 // Fired before an `insert` or `update` query.
12 // beforeSave: async (model, attrs, options) => {},
13
14 // After saving a value.
15 // Fired after an `insert` or `update` query.
16 // afterSave: async (model, response, options) => {},
17
18 // Before fetching a value.
19 // Fired before a `fetch` operation.
20 // beforeFetch: async (model, columns, options) => {},
21
22 // After fetching a value.
23 // Fired after a `fetch` operation.
24 // afterFetch: async (model, response, options) => {},
25
26 // Before fetching all values.
27 // Fired before a `fetchAll` operation.
28 // beforeFetchAll: async (model, columns, options) => {},
29
30 // After fetching all values.
31 // Fired after a `fetchAll` operation.
32 // afterFetchAll: async (model, response, options) => {},
33
34 // Before creating a value.
35 // Fired before an `insert` query.
36 // beforeCreate: async (model, attrs, options) => {},
37
38 // After creating a value.
39 // Fired after an `insert` query.
40 // afterCreate: async (model, attrs, options) => {
41 afterCreate: async entry => {
42 axios
43 .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, {})
44 .catch(() => {
45 // Ignore
46 });
47 },
48
49 // Before updating a value.
50 // Fired before an `update` query.
51 // beforeUpdate: async (model, attrs, options) => {},
52
53 // After updating a value.
54 // Fired after an `update` query.
55 // afterUpdate: async (model, attrs, options) => {
56 afterUpdate: async entry => {
57 axios
58 .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, {})
59 .catch(() => {
60 // Ignore
61 });
62 },
63
64 // Before destroying a value.
65 // Fired before a `delete` query.
66 // beforeDestroy: async (model, attrs, options) => {},
67
68 // After destroying a value.
69 // Fired after a `delete` query.
70 // afterDestroy: async (model, attrs, options) => {
71 afterDestroy: async entry => {
72 axios
73 .post(strapi.config.currentEnvironment.staticWebsiteBuildURL, {})
74 .catch(() => {
75 // Ignore
76 });
77 },
78};
Install Axios
Your new code changes require the installation of an npm package called, axios
.
From you command line:
Path: ./cms
1npm i axios --save
Commit and Push to Heroku and Update Netlify
You will now need to add
, commit
and push
your changes in the project. These changes were made in the Strapi files. Doing this will automatically fire a Post
request to Netlify, which will update Netlify automatically.
From your command line:
Path: ./cms/
1git add .
2git commit -m “added webhook for netlify”
3heroku login
4git push heroku master
Webhooks configured
After Netlify has had a moment to issue the command to rebuild and has done so, you will be able to login into your Heroku based Strapi project and make updates which automatically update Netlify.
Additional Content Types
In this example tutorial we created one Content-Type called, article
. You will need to update the model file (as above) for every additional Content-Type you create for your project AND which should trigger a Gatsby rebuild
.
13. Adding Markdown Support
Important links from Video:
- GitHub Tutorial Repo
- Final Netlify Demo URL - Markdown Demo Page
- React Markdown
- Cloudinary
- Gatsby Environment Variables
Adding Markdown Support
The next steps involve adding Markdown support to the Gatsby build. In this way, your content from Strapi will properly transform from Markdown to HTML.
In this example, the tutorial article, "Bed and breakfasts Give a Personal Touch", the main content area is not properly formatted.
At the end of this section, the content will properly transform Markdown to HTML. You can see the final transformation here.
A React package called React Markdown
needs to be installed in order properly parse the Markdown and transform it to HTML.
Install React Markdown
The package repo can be found at React Markdown.
From your command line:
Path: ./blog/
1npm install --save react-markdown
Use React Markdown in a Component
Next, several steps need to occur. These steps include importing the package into each of the index.js
, article.js
, and author.js
template pages. And then, adding the React component.
The import statement looks like this:
1import ReactMarkdown from "react-markdown"
And the ReactComponent for the article.js
file looks like this:
1<ReactMarkdown
2 source={document.node.content}
3/>
Note: The source
option from react-markdown
is simply accepting the content from the graphQL query. You will need to also delete <p>{document.node.content}</p>
from the markup.
Path: ./blog/src/templates/article.js
The complete article.js
code looks like this at this point:
1import React from "react"
2import { Link, graphql } from "gatsby"
3import Img from "gatsby-image"
4import Layout from "../components/layout"
5import ReactMarkdown from "react-markdown"
6
7const ArticleTemplate = ({ data }) => (
8 <Layout>
9 <h1>{data.strapiArticle.title}</h1>
10 <p>
11 by{" "}
12 <Link to={`/authors/User_${data.strapiArticle.author.id}`}>
13 {data.strapiArticle.author.username}
14 </Link>
15 </p>
16 <Img fluid={data.strapiArticle.image.childImageSharp.fluid} />
17 <ReactMarkdown source={data.strapiArticle.content} />
18 </Layout>
19)
20
21export default ArticleTemplate
22
23export const query = graphql`
24 query ArticleTemplate($id: String!) {
25 strapiArticle(id: { eq: $id }) {
26 title
27 content
28 image {
29 childImageSharp {
30 fluid(maxWidth: 960) {
31 ...GatsbyImageSharpFluid
32 }
33 }
34 }
35 author {
36 id
37 username
38 }
39 }
40 }
41`
You have to repeat these steps for the index.js
and author.js
.
Note: There source
option is different as each of these templates are querying the data differently than the article.js
file.
Path: ./blog/src/templates/author.js
The complete author.js
code looks like this at this point:
Note: You will need to also delete <p>{article.content}</p>
from the markup.
1import React from "react"
2import { Link, graphql } from "gatsby"
3import Layout from "../components/layout"
4import ReactMarkdown from "react-markdown"
5
6const UserTemplate = ({ data }) => (
7 <Layout>
8 <h1>{data.strapiUser.username}</h1>
9 <ul>
10 {data.strapiUser.articles.map(article => (
11 <li key={article.id}>
12 <h2>
13 <Link to={`/Article_${article.id}`}>{article.title}</Link>
14 </h2>
15 <ReactMarkdown source={article.content} />
16 </li>
17 ))}
18 </ul>
19 </Layout>
20)
21
22export default UserTemplate
23
24export const query = graphql`
25 query UserTemplate($id: String!) {
26 strapiUser(id: { eq: $id }) {
27 id
28 username
29 articles {
30 id
31 title
32 content
33 }
34 }
35 }
36`
Path: ./blog/src/pages/index.js
The complete index.js
code looks like this at this point:
Note: You will need to also delete <p>{document.node.content}</p>
from the markup.
1import React from "react"
2import { Link, graphql } from "gatsby"
3import Img from "gatsby-image"
4import Layout from "../components/layout"
5import ReactMarkdown from "react-markdown"
6
7const IndexPage = ({ data }) => (
8 <Layout>
9 <h1>Hi people</h1>
10 <p>Welcome to your new Gatsby site.</p>
11 <p>Now go build something great.</p>
12 <ul>
13 {data.allStrapiArticle.edges.map(document => (
14 <li key={document.node.id}>
15 <h2>
16 <Link to={`/${document.node.id}`}>{document.node.title}</Link>
17 </h2>
18 <Img fixed={document.node.image.childImageSharp.fixed} />
19 <ReactMarkdown source={document.node.content} />
20 </li>
21 ))}
22 </ul>
23 <Link to="/page-2/">Go to page 2</Link>
24 </Layout>
25)
26
27export default IndexPage
28
29export const pageQuery = graphql`
30 query IndexQuery {
31 allStrapiArticle {
32 edges {
33 node {
34 id
35 image {
36 childImageSharp {
37 fixed(width: 200, height: 125) {
38 ...GatsbyImageSharpFixed
39 }
40 }
41 }
42 title
43 content
44 }
45 }
46 }
47 }
48`
If you take a look at your project, you will see that the Markdown is now properly transforming into HTML. However, still missing is the ability to parse images from within the content.
Use Images with your Content
Strapi easily saves your images to whichever Provider
is configured. In this tutorial, it is Cloudinary
. However, not all projects will use Cloudinary
and in development, images are often saved to Strapi locally. Therefore, you will need to set an environment variable and instruct Gatsby how to parse the image path
.
Setting and using environment variables
is a big subject. This Gatsby article does a good job explaining how Gatsby uses them.
In this tutorial, an environment variable is used to prepend http:localhost:1337
to the image path
for image uploaded in Development (gatsby develop
) as Strapi is saving the images locally.
Path: ./blog/
In the Gatsby project root
create a file and call it .env.development
. Add the following line:
1IMAGE_BASE_URL=http://localhost:1337
This has created a variable called IMAGE_BASE_URL
which the Reactmarkdown
component will use IF the image path does not have a complete URL.
React-markdown
has an option called, transformImageUri. This option makes the image path available for use within the component and so within its value pair, a ternary operator will be used to provide the logic and check if its a complete path or not. If it is not a complete path, the env variable will be used to create one.
In index.js
the component now looks like this:
Path: ./blog/src/pages/index.js
1<ReactMarkdown
2 source={document.node.content}
3 transformImageUri={uri => uri.startsWith('http') ? uri : `${process.env.IMAGE_BASE_URL}${uri}`}
4/>
Edit the article.js
and author.js
and add the transformImageUri
option to their <ReactMarkdown>
components:
Path: ./blog/src/templates/article.js
1<ReactMarkdown
2 source={data.strapiArticle.content}
3 transformImageUri={uri => uri.startsWith('http') ? uri : `${process.env.IMAGE_BASE_URL}${uri}`}
4/>
Path: ./blog/src/templates/author.js
1<ReactMarkdown
2 source={article.content}
3 transformImageUri={uri => uri.startsWith('http') ? uri : `${process.env.IMAGE_BASE_URL}${uri}`}
4/>
NOTE: This simple checks if uri
starts with http
, if it does then it's a complete path and if it doesn't then it is locally hosted with a relative path and the IMAGE_BASE_URL
is prepended.
Note: You can check if this works by going to Plugins > FILES UPLOAD > cog
and changing the Provider back from Cloudinary
to Local Provider
. You will need to add back your images from within your Content Types to test this.
You content is now properly parsed and transforming from Markdown to HTML. The following section is an Optional section that will provide some styling (and instruction) for the index.js
and author.js
pages and also implement and allow the use of plain HTML within the content.
OPTIONAL: Creating a Basic Blogroll
The index.js
page currently displays every article
. The issue is that the page displays the entire article. Normally, on this type of index page, a snippet is showed with a Read more
link.
To accomplish this functionality various things need to be done:
- Add a CSS class through the
react-markdown
package and component - This CSS class allows for removing the images as well as give a uniform height with CSS for the content in the
index
type pages. - Add JavaScript to omit any text after
500
characters and add...
to the end of the snippet. - Add a link for the
Read more
. - Add a
global.css
stylesheet with a few styles.
These changes are the same for both the index.js
page and the author.js
template. Edit these files like this:
index.js
Path: ./blog/src/pages/index.js
1<ReactMarkdown
2 source={document.node.content.substring(0, 500).concat("...")}
3 transformImageUri={uri => uri.startsWith('http') ? uri : `${process.env.IMAGE_BASE_URL}${uri}`}
4 className="indexArticle"
5/>
6
7<Link to={`/${document.node.id}`}>Read more</Link>
author.js
Path: ./blog/src/templates/author.js
1<ReactMarkdown
2 source={article.content.substring(0, 500).concat("...")}
3 transformImageUri={uri => uri.startsWith('http') ? uri :
4 `${process.env.IMAGE_BASE_URL}${uri}` }
5 className="indexArticle"
6/>
7
8<Link to={`/Article_${article.id}`}>Read more</Link>
NOTE: Make sure the above code is within the closing li tag.
Add the CSS
Path: ./blog/src/
Create a folder and call it styles
.
Path: ./blog/src/styles/
Create a file called global.css
Within the global.css
file, add the following styles to provide a uniform height to each of your snippets
and Read more
links. The CSS will also hide any images within the content there.
Note: The follow CSS styles target the className
option above.
1.indexArticle {
2 max-height: 250px;
3 overflow: hidden;
4}
5
6.indexArticle img {
7 display: none;
8}
Link the CSS file
In order to use this new global.css
file, you need to import it at the top of each page and template.
For example, for the index page
, add import "../styles/global.css
Path: ./blog/pages/index.js
1import React from "react"
2import { Link, graphql } from "gatsby"
3import Img from "gatsby-image"
4import Layout from "../components/layout"
5import ReactMarkdown from "react-markdown"
6
7import "../styles/global.css"
Add the import statement for each of the other pages you would like to have global CSS Styles for.
OPTIONAL: Adding plain HTML support to the markdown
Your project has index
pages that show snippets and provide your users a link to read the full article. The next optional part of this section is to add HTML-in-Markdown
support to your markdown.
By default, react-markdown
escapes HTML contained with the markdown. This is done when the editing environment is not controlled and unwanted code injections are being guarded against. However, with the Strapi editor
this is not a problem and there are various scenarios where supporting HTML-in-Markdown
is desirable.
In this tutorial, the use case demonstrated is the ability to add classes to the images within the content. It is expected that your CSS will have a default size for the content images. In this case, using markdown syntax for the images is perfect.
For smaller, larger or floated images, for example, HTML support is needed as markdown does not natively support adding classes within the editing experience.
There are two steps to configure your project to allow HTML-in-Markdown
:
- Add the
react-markdown
option that sets theescapeHTML={false}
from{true}
- Add a few CSS classes for
.small
and.large
CSS classes.
Set the 'escapeHTML' option
React-markdown
sets an option called, escapeHTML
to true
by default. You need to set this to true. Add the escapeHTML={false}
option to your <Reactmarkdown />
component. Like this:
For the article.js
Path: ./blog/src/templates/article.js
1<Reactmarkdown
2 source={article.content.substring(0, 500).concat("...")}
3 transformImageUri={ uri =>
4 uri.startsWith("http")
5 ? uri
6 : `${process.env.IMAGE_BASE_URL}${uri}` }
7 className="articleContent"
8 escapeHtml={false}
9 />
NOTE: Add escapeHTML={false}
to the index.js
and author.js
files in the same way.
Add the classes to the CSS
In this tutorial, two classes are demonstrated. They are added to the global.css
file.
Path: ./blog/src/styles/global.css
1.articleContent img {
2 display: block;
3 margin: 0 auto;
4 width: 400px;
5}
6
7.articleContent .small {
8 width: 100%;
9 max-width: 250px;
10}
11
12.articleContent .large {
13 width: 100%;
14 max-width: 600px;
15}
This CSS gives a standard size and centers any images added with markdown. And images can now be added with HTML directly in markdown and with the classes added.
For example,
1<img class="small" src="path-to-image/gatsby.png" alt="Small Gatsby Logo" />
Update Git repo for the project to update Netlify
Netlify makes it easy to update the project. Once you push to GitHub, Netlify will automatically rebuild the project.
Path: ./blog/
1git add .
2git commit -m "added markdown support"
3git push
After a few minutes, your Gatsby project hosted on Netlify will have its files updated and you can go to your Strapi installation on Heroku and add an article
Content Type which will now use and properly display markdown.
Conclusion
Congrats! You’ve successfully built a super fast and easy-to-maintain blog!
Since the content is managed by Strapi, the authors can write articles through a nice UI and developers only have to rebuild the Gatsby blog in order to update the content.
Where to go next?
Feel free to continue this project to discover both Gatsby and Strapi advantages. Here are some features you can add: a list of authors, article categories, and comment system with the Strapi API or Disqus. You can also create other types of websites (e-commerce shop, corporate website, etc.).
When your project is achieved, you will probably want to deploy it. The static website generated by Gatsby can easily be published on storage providers: Netlify, S3/Cloudfront, GitHub pages, GitLab pages, Heroku, etc. The Strapi API is a headless CMS, so it can be hosted on Heroku or any Linux instance that has Node.js installed.
The code source of this tutorial is available on GitHub. To see it live, clone the repository, run npm run setup
, start the Strapi server (cd cms && strapi start
) and the Gatsby server (cd blog && gatsby develop
).
We hope you enjoyed this tutorial. Feel free to comment on it, share it, and let us know how you create sites built with React and how you manage their content.
Please note: Since we initially published this blog, we released new versions of Strapi and tutorials may be outdated. Sorry for the inconvenience if it's the case, and please help us by reporting it here.
Get started with Strapi by creating a project, using a starter or trying our instant live demo. Also, consult our forum if you have any questions. We will be there to help you.
See you soon!
Pierre created Strapi with Aurélien and Jim back in 2015. He's a strong believer in open-source, remote and people-first organizations. You can also find him regularly windsurfing or mountain-biking!