If you are familiar with our blog, you must have seen that we've released a series of tutorials to make blogs using Strapi with a variety of frontend frameworks: React, Next.js, Vue, Nuxt.js, or Angular.
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, Gatsby, 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.
With more than 34,000 stars on GitHub, Jekyll is the most famous static website generator.
Developed on top of Ruby, Jekyll makes static website creation super easy. It includes many features such as permalinks, categories, pages, and custom layouts. Write some Markdown files, customize your templates and you will get an easy-to-host website in seconds.
Last but not least, Jekyll is the static website generator powering GitHub Pages!
Strapi is the open-source Headless CMS. It saves weeks of API development time and allows easy long-term content management through a beautiful administration panel anyone can use.
Unlike other CMSs, Strapi is 100% open-source, which means:
The goal here is to be able to create a simple static blog website using Strapi as the backend and React for the frontend. The source code is available in this repository. We will make this tutorial shorter and more efficient by using our new templates.
This tutorial will always use the latest version of Strapi. That is awesome right!? You'll understand why below. You need to have node v.12 installed and that's all.
Create a blog-strapi
folder and cd
into it by running the following commands:
mkdir blog-strapi
cd blog-strapi
That's the easiest part of this tutorial thanks to Rémi who developed a series of Strapi templates that you can use for your Blog, E-commerce, Portfolio, or Corporate website project.
These templates are Strapi applications containing existing collection types and single-types suited for the appropriate use case, and data.
In this tutorial, we'll use the Blog template and connect a static Jekyll website to it.
Note: for this tutorial, we will be using
yarn
as our package manager.
Create your Strapi backend folder using the Blog template.
yarn create strapi-app backend --template blog
Don't forget that Strapi is running on http://localhost:1337. Create your admin user by signing up!
That's it! You're done with Strapi! I'm not kidding, we can start to create our Jekyll website now in order to fetch our content from Strapi. But before that, let's talk about this amazing template you just created.
You should know that before the starters and before the templates, we only had tutorials. The idea of creating starters came to us when we realized that we could do something with the end result of our tutorials. Thus were born our starters.
However, Strapi evolves quickly, very quickly and at the time the starters constituted a repository including the backend as well as the frontend. This means that updating the Strapi version on all our starters took time, too much time. We then decided to develop templates that are always created with the latest versions of Strapi. Quite simply by passing in parameter the repository of the desired template like you just did. Also, it gives you a good architecture for your Strapi project.
These templates provide a solid basis for your Strapi application:
Feel free to modify all of this set-up according to your needs.
Nice! Now that Strapi is ready, you are going to create your Jekyll application.
The easiest part has been completed. Let's get our hands dirty developing our blog!
##Requirements
gem install jekyll bundler
If you have any issue installing Jekyll, please take a look at the Jekyll's documentation or at this issue.
Create a Jekyll frontend
folder by running the following command:
jekyll new frontend
Once the installation is complete, you can start the server:
cd frontend
bundle exec jekyll serve
# => Now browse to http://localhost:4000
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.
By default, Jekyll uses Markdown files to manage data. Fortunately, thanks to the plugin system, you can get data from any source.
To connect Jekyll to a new source of data, you have to develop a new plugin. Several plugins already exist, so one of them should fill your needs.
In this example, we are using Strapi. We are going to need a plugin compatible with Strapi APIs. Good news: we built it for you!
Add the jekyll-strapi
gem to your Gemfile
:
1 source "https://rubygems.org"
2 # Hello! This is where you manage which Jekyll version is used to run.
3 # When you want to use a different version, change it below, save the
4 # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
5 #
6 # bundle exec jekyll serve
7 #
8 # This will help ensure the proper Jekyll version is running.
9 # Happy Jekylling!
10 gem "jekyll", "~> 4.2.0"
11 # This is the default theme for new Jekyll sites. You may change this to anything you like.
12 gem "minima", "~> 2.5"
13 gem "jekyll-strapi"
14 # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
15 # uncomment the line below. To upgrade, run `bundle update github-pages`.
16 # gem "github-pages", group: :jekyll_plugins
17 # If you have any plugins, put them here!
18 group :jekyll_plugins do
19 gem "jekyll-feed", "~> 0.12"
20 end
21
22 # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
23 # and associated library.
24 platforms :mingw, :x64_mingw, :mswin, :jruby do
25 gem "tzinfo", "~> 1.2"
26 gem "tzinfo-data"
27 end
28
29 # Performance-booster for watching directories on Windows
30 gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
Install the gem by running the following command:
bundle install
Then add jekyll-strapi
to your plugins list in the _config.yml
file:
1 ...
2 theme: minima
3 plugins:
4 - jekyll-feed
5 - jekyll-strapi
6 ...
This plugin needs some configuration. At the end of the _config.yml
file, add the following code:
1 theme: minima
2 plugins:
3 - jekyll-feed
4 - jekyll-strapi
5
6 strapi:
7 # Your API endpoint (optional, default to http://localhost:1337/api)
8 endpoint: http://localhost:1337/api
Now we want to display the list of articles. To do so, we are going to instruct Jekyll to retrieve the list of articles from Strapi:
1strapi:
2 # Your API endpoint (optional, default to http://localhost:1337/api)
3 endpoint: http://localhost:1337/api
4 collections:
5 articles:
6 # Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/api/foo`.
7 type: articles
Each content type must be listed in the collections
object. The type
field is used to build the URL requested. For example, if your type is Articles, the requested URL will be [http://localhost:3000/api/articles](http://localhost:3000/api/articles)
. The permalink is the URL structure you want to use for your blog posts. We could have chosen /api``/articles/:id
, but slugs are more friendly.
After that, we need to display the data. Jekyll uses a theme system. By default, the used theme is minima. The theme's files are not generated in the Jekyll projects, but you can override every theme's template by creating a file with the same name in the _layouts
folder.
To replace the existing home page content, create the folder _layouts
with home.html
inside it:
1 ---
2 layout: default
3 ---
4
5 <div class="home">
6 <h1 class="page-heading">Articles</h1>
7 {%- if strapi.collections.articles.size > 0 -%}
8 <ul class="article-list">
9 {%- for article in strapi.collections.articles -%}
10 <li>
11 <span class="article-meta">{{ article.publishedAt | date_to_string }}</span>
12 <h3>
13 <a class="article-link" href="/articles{{ article.slug | relative_url }}">
14 {{ article.title }}
15 </a>
16 </h3>
17 <!-- Display an excerpt of the article -->
18 <p>{{ article.content | markdownify | strip_html | truncatewords: 10 }}</p>
19 </li>
20 {%- endfor -%}
21 </ul>
22 {%- endif -%}
23 </div>
Finally, reload your app to see the changes.
layout
that we want to use to display the header and the footer.jekyll-strapi
exposes the data received from the API through the global variable strapi
, which is accessible from every template. To display the list of posts, we checked that the list strapi.collections.articles
is not empty. If it is the case, we loop on it to display each item.|
. The vertical line symbol is used by Jekyll's filters, which alter the way to display text. For example, article.publishedAt
uses the data_to_string
to display the post's creation date in a more human friendly way.url
which represents the url of the record's page based on the permalink given in the configuration.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.
First, we want to be sure to display images. and to do this we need to use env
variable to fetch the url of the Strapi project depending on the environment.
Create a _plugins/env.rb
file containing the following:
1 module Jekyll
2 class EnvVariables < Generator
3 def generate(site)
4 site.config['env'] = {}
5 ENV.each_pair { |k, v| site.config\['env'\][k] = v }
6 end
7 end
8 end
This will fetch all your env variable and make them available in site.env
.
Create an API_URL
env variable on your machine by running the following command and then restart the server:
export API_URL=http://localhost:1337/api
Let's create the template and define the content displayed in a new file named article.html
located in the _layouts
directory:
1 ---
2 layout: default
3 ---
4
5 <img src="{{ site.env.API_URL | append: page.document.image.url }}">
6 <h1>{{page.document.title}}</h1>
7 <span class="post-meta">{{ page.document.publishedAt | date_to_string }}</span>
8 {{ page.document.content | markdownify }}
The template displays the title of the article, some metadata and converts the content from Markdown to HTML.
In the _config.yml
file, we must add layout
and output
lines to indicate to Jekyll that we want to generate a new page for each article, using the template we created previously:
1 strapi:
2 # Your API endpoint (optional, default to http://localhost:1337/api)
3 endpoint: http://localhost:1337/api
4 collections:
5 articles:
6 # Collection name (optional). Used to construct the URL requested. Example: type `foo` would generate the following url `http://localhost:1337/api/foo`.
7 type: articles
8 permalink: /articles/:slug/
9 layout: article.html
10 output: true
After restarting the Jekyll server, you should be able to see a new folder named articles
, in the _site
folder, containing the generated pages.
From now on, you can visit the detail page by clicking on URLs displayed on the homepage.
Articles belong to a category. Let's create a page per category.
Create a _layouts/category.html
file and add the following code to it:
1 ---
2 layout: default
3 ---
4
5 <h1>{{ page.document.name }}</h1>
6
7 {%- if page.document.articles.size > 0 -%}
8 <ul class="article-list">
9 {%- for article in page.document.articles -%}
10 <li>
11 <span class="article-meta">{{ article.publishedAt | date_to_string }}</span>
12 <h3>
13 <a class="article-link" href="/articles{{ article.slug | relative_url }}">
14 {{ article.title }}
15 </a>
16 </h3>
17 <!-- Display an excerpt of the article -->
18 <p>{{ article.content | markdownify | strip_html | truncatewords: 10 }}</p>
19 </li>
20 {%- endfor -%}
21 </ul>
22 {%- endif -%}
Add the collection type in your _config.yml
file:
1 strapi:
2 # Your API endpoint (optional, default to http://localhost:1337)
3 endpoint: http://localhost:1337
4 collections:
5 # Example for a "posts" collection
6 articles:
7 # Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
8 type: articles
9 permalink: /articles/:slug/
10 layout: article.html
11 output: true
12
13 categories:
14 # Collection name (optional). Used to construct the url requested. Example: type `foo` would generate the following url `http://localhost:1337/foo`.
15 type: categories
16 permalink: /categories/:name
17 layout: category.html
18 # Generate output files or not (default: false)
19 output: true
Update the _layouts/home.html
file with the following code:
1 ---
2 layout: default
3 ---
4
5 <div class="home">
6 <h1 class="page-heading">Articles</h1>
7 {%- if strapi.collections.articles.size > 0 -%}
8 <ul class="article-list">
9 {%- for article in strapi.collections.articles -%}
10 <li>
11 <span class="article-meta">{{ article.publishedAt | date_to_string }}</span>
12 <h3>
13 <a class="article-link" href="/articles{{ article.slug | relative_url }}">
14 {{ article.title }}
15 </a>
16 -
17 <a href="/categories/{{ article.category.name | relative_url }}">
18 ({{ article.category.name}})
19 </a>
20 </h3>
21 <!-- Display an excerpt of the article -->
22 <p>{{ article.content | markdownify | strip_html | truncatewords: 10 }}</p>
23 </li>
24 {%- endfor -%}
25 </ul>
26 {%- endif -%}
27 </div>
This includes a link to the category an article belongs to.
Finally, restart the server and visit any category page.
Huge congrats, you have successfully finished this tutorial. I hope you enjoyed it.
Feel free to add additional features, adapt this project to your own needs, and give your feedback in the comment section below.
Quadri Sheriff is an aspiring technical writer and a software programmer. He is a very shy individual who loves writing, coding and reading in his spare time. He is currently interested in learning more about blockchain and the Jamstack.