How I Created My Blog Using JAMStack
In the first two articles of this series, we explored JAMStack (what it is, its components and architecture, available tools for JAMStack development, its pros and cons, and comparison between WordPress and JAMStack). If you haven't read it yet, I highly suggest you give it a read first.
- What Is JAMStack And Whether You Should Use It For Your App?
- JAMStack vs. WordPress: Which One Is Better?
For the remainder of this series, I'll walk you through the process of how I created my personal blog with JAMStack - a modern web development practice. But before we jump into our first tutorial, let's review the entire process at the high level and some "gotchas" and challenges I discovered along the way and how I overcame those challenges.😎
My decision to set up my own blog as well as my decision to use JAMStack came a long way. I originally started blogging on DEV Community. DEV is really a great community, don't get me wrong, but I was in need of a blogging platform that would offer some amount of flexibility and customization of how my blog should look like. Also, I thought it would be great to start growing my personal "brand", and having your own blog with your own domain name would be a good starting point.
So I set out to look for a way to cross-post content between my blog on DEV Community and my to-be-created blog with its own domain name. I quickly noticed that DEV actually has an extension that would allow you to generate a personal blog from your DEV Community posts using Stackbit. Great! "This is exactly what I need", I said to myself. I then followed some tutorials trying to set up my own blog on Stackbit.👩💻
However, I quickly ran into issues migrating my posts from DEV Community into Stackbit. I emailed Stackbit's support team and was told that they were aware of the issue and have been working on fixing it. Bummer!😞
I could either wait until Stackbit fixes the issue or find another solution. I decided to find another solution simply because I just don't like the fact that I have to rely on someone else to fix the problem, and that's just the nature of using a site builder like Stackbit, which is aimed toward less technical users.
So my mission now is to find another solution, which I will explain in more detail in the next section. However, I think it's important to acknowledge the fact that my decision to use JAMStack as well as what tools to use to build my JAMStack app started with Stackbit and is heavily influenced by it. After all, I learned about Netlify, Gatsby, and even Ghost CMS from my initial attempt with Stackbit because it uses JAMStack.
JAMStack components recap
Let's quickly recap all the components of our JAMStack blog and the technologies that we will be using for each of the components.
Static site generator
There are two sources of HTML for our blog: the static HTML contents (site header, logo, layout, footer, etc.) and the dynamic HTML contents from the actual blog posts. We need to somehow combine both of these static and dynamic HTML sources into a single HTML file at every single build of our app. Static site generator to the rescue!🦸♂️
A static site generator is a software application that creates HTML pages from templates or components and a given content source during a build process. There are many static site generators available out there. We will be using Gatsby for our blog.
During a build, Gatsby loads JSON data from GraphQL and merges it with components to create HTML pages. These generated pages are then deployed to a web server. When the server receives a request from a browser, it responds with rendered HTML.
So the question that needs to be answered now is where does the GraphQL data come from? 🤔. I'm glad you asked because that's exactly what we're going to explore in the next section.😉
Content Management System (CMS)
Dynamic contents for JAMStack sites (in our case, these are our blog posts) can be controlled via a CMS, typically known as headless CMS. Once a change is made in CMS (a post is published/added/edited/deleted), a new build of our site will be triggered and deployed as static assets. Similar to static site generators, there are many options for CMS available out there, but we will be using Ghost CMS for our blog.
As mentioned above, after a change is made to either our static HTML from Gatsby or to our dynamic HTML from Ghost CMS, we will need to somehow trigger the deployment to the web server to rebuild and regenerate the HTML files. How are we going to do that?🤔 Again, glad you asked! Join me in the next section!😎
The generated HTML pages need to be hosted on a web server somewhere in order to allow users from anywhere to access our blog. There are several services available, but we will be using Netlify for our blog.
I chose Netlify because it has an awesome free plan that comes with great features such as:
- Generous monthly build minutes and bandwidth (300 build minutes/month and 100GB/month)
- Automated CI/CD: Connect Netlify to your GitHub repo where you're hosting your Gatsby code and integrate Netlify build hooks with Ghost CMS to automatically trigger the build every time a change is made from either of those two sources.
- Custom domain management: You will have to pay for your own custom domain if you decide to purchase it from Netlify, but domain setup and management are seamless with Netlify.
Now that you understand all these components at a high level, I'll share with you some of the challenges that I encountered as I was setting up my blog.
Gatsby static site generator
In order to get my site up and running as quickly as possible, I decided to use one of Gatsby's starter libraries. Starters are open-source Gatsby sites maintained by Gatsby that enable users to dive into their next Gatsby project with minimum effort. Starters range from minimal boilerplate to full proof of concept. Since we will be using Ghost as our content management system. It seems logical that the gatsby-starter-ghost is the best option for us.
Besides a few customizations to give the blog the look and feel of my personal brand, the following features were implemented/improved to suit my needs:
- Added a Tags page that displays my posts grouped by their corresponding tags.
- Added Google Analytics
- Added Algolia Search
- Added block code syntax highlight using highlight.js
Ghost offers Ghost(Pro) - a managed hosting service for Ghost that offers users the fastest way to get started on Ghost. It includes out-of-the-box features such as custom domain, custom themes, server maintenance and backups, CDN, etc. However, since I was looking for a low-cost option, I opted for a self-hosted instance.
Out of the box, Ghost comes with:
- A core JSON API
- An admin client app
- A front-end theme layer using Handlebars templating languages
However, since I use Gatsby for the frontend theme layer, I had to modify a few things after installing Ghost. Ghost's Admin Client app has the page preview feature that only works if you use one of Ghost's themes. Therefore, I had to set up a proxy server with some URL redirect configuration in order to be able to preview my posts with my Gatsby theme from the Admin Client app. The page preview on the Branding setting page still doesn't work, but that didn't bother me much, so I didn't spend time fixing it. More on that later when we get to the tutorials.
As mentioned above, we will use Netlify to manage automatic build and deployment of our site. Basically, we will connect Netlify to our GitHub repo where we store our Gatsby code and configure it so that every time a change is pushed to the remote repo, a build is triggered in Netlify. In addition to that, we will integrate Netlify's build hook with Ghost so that every time a change is made in Ghost (you can configure what type of changes you want such as post added, post updated, global changes, etc.), a build in Netlify is automatically triggered.
Unless you're planning on hosting your Ghost server on your local machine, which you can if you want, you will need to pick a cloud platform (AWS, Azure, Heroku, Digital Ocean, etc.) to host your server app. Since my goal is to come up with a low-cost solution, here is what I ended up using for my stack:
- Use Heroku to host my Ghost server, which is essentially a Node.js app. I found this GitHub repo that can be used to deploy a Ghost server into Heroku with just a click of a button. However, this app is preconfigured to use JawsDB as the MySQL database where all data for our posts are stored. JawsDB does have a free plan, but it only comes with 5MB of storage. The next price tier is $10/month for which you'll get 1GB of data. I needed to come up with a lower-cost option for my data storage.
- I ended up using AWS RDS for my MySQL database. If you sign up for a free tier account with AWS, you're eligible for 750 hours of RDS instances and 20GB of storage. Even if after you have used up your free tier credits, the cost to host a MySQL database on Amazon RDS is still much lower compared to JawsDB. Therefore, I needed to modify the code in the GitHub repo to re-configure the add-ons. More on that later!
As mentioned above, in order to fix the site preview issue in Ghost, I had to create a proxy server, which is essentially a Node.js app, which is also hosted on Heroku.
My blogging workflow
With this setup, here is my typical workflow just so that you can understand what it looks like:
- Edit site template
- Edit and test site locally
- Commit and push changes to GitHub
- Netlify automatically builds and deploys the site
- Publish new content
- Add/remove/edit posts locally and publish from the Ghost Admin Client app
- Netlify automatically builds and deploys the site based on change detection settings in Netlify's build hook. Below is an image, taken from Ghost's website, just to give you an idea of what the UI for the Admin Client app looks like.
That's it. Sounds simple, huh?😎 Well, if you like what you hear and are still interested, join me in the next part of this series where I will be sharing tutorials on how I set up my site. See you there! 👋