How we Built our Website with Ghost and a Static Site Generator

October 26, 2020 Karl Clement 7 min read

TL;DR - We are using Eleventy and Gulp to generate individual HTML pages from Nunjucks templates. The content is saved as Markdown files and JSON collections for repeating styles. For blog and podcast content, we're using a Ghost self-hosted instance as our CMS API. Newsletter is handled by AWS SES and finally AWS Lambda serverless functions to handle our backend magic. All in all, development took approximately 13 full business days to complete this project.

Why do we care?

Every technical decision is a serious decision. As much as we all preach "moving fast and breaking things", we still need to consider the amount of technical debt we are slowly creating with every decision. That being said, there's a clear sweet spot where you optimize for future flexibility while simultaneously allowing you to move quickly to build your product.

Some builds are larger than others. Let's take a SaaS product like Basecamp for example. You may choose to build your main product off a larger monolithic base such as Ruby on Rails or to separate each piece into multiple units to offer you more flexibility. Either way, you need to consider the balance between speed and flexibility. For Dignified, we decided to take a more fragmented micro-service approach and separate tasks into smaller pieces to avoid creating too much technical debt.

If you are interested in a breakdown comparison of a micro-service approach over a monolithic approach, send me a tweet @karlclement!

How we Decided

All of our choices were based on a few guiding rules:

  • Anyone can regularly add new content
  • We have multiple content types with varying visual representations
  • We have a custom design
  • The website must render as fast as possible while fully implementing SEO tactics
  • Lightweight server footprint with minimal maintenance

These items allowed us to pick and choose the tools we needed that fit the criteria. We can easily maintain a balance between speed and flexibility without diminishing the user's experience.

The Breakdown

This is where it get's a bit technical, feel free to skip if you aren't interested in the implementation.

We started by separating our backend operations from our frontend rendering. This allows us to take advantage of SEO benefits and faster page loads while using multiple remote sources of content. This would also require static pages generated for every page on the site. Every time we update our content, each new page must be generated and deployed.

There are multiple libraries to help you generate static websites. Some of the most notable candidates are Jekyll, Hugo, Hexo, Eleventy, Gatsby and Nextjs. Gatsby and NextJs are heavily dependant on ReactJs for your component library. Jekyll, Hugo and Hexo have specific templating patterns to generate content, similar to Wordpress.

Finally we decided to use Eleventy. Eleventy allows you to create any kind of template, with the templating language you want. It also allows you to pull content from locally available files or even hosted REST APIs.

The Content

Since Eleventy allows you to pull content from external sources, we decided to use a very popular blogging platform known as Ghost. Other good candidates for external CMS platforms are Netlify CMS, Strapi, Forestry, Prismic, Contently and many more.

The only content we decided to pull from Ghost were blog posts and podcast summary posts. Since these two post types seem to follow a traditional blog post pattern, it was easy to create a template for each of these types in Eleventy.

Projects are then generated from a JSON content file with details and descriptions of each project we have worked on. This includes images, callouts, and calls to action. We needed to create a custom template with Eleventy for the project content type.

Templating

Eleventy is very flexible when creating templates. You have the option to use Nunjucks, EJS, Handlebars, Mustache, Haml and many others. We decided to use the Nunjucks templating library since it allowed us to embed more complex Javascript operations and macros in our templates.

With Nunjucks, we created individual templates to use each of the data types described above. Nunjucks also allows you to create partials and macros to be embeded in multiple places on the site similar to React or Angular components. These reusable pieces can also be used to layout templates used to provide a visual base for your template. In our case, we have three types of layout: a darker theme, lighter theme, and the sidebar theme.

To compile the Javascript, SCSS (Sass CSS) and HTML together, we used GulpJs. This allowed us to create a build script with commands to compile, convert, and compress our Javascript and SCSS in browser compatible code. We can also use these commands to prepare files for deploy to a production environment.

Hosting

Since we separated our platform into three main components, our frontend could be hosted on an entirely static platform (no need for a database or data processing). You have quite a few options for static hosting including Netlify, AWS S3, Surge.sh, Render, etc. Since we already love Render, we chose their static hosting solution. A huge benefit to Render is the deploy webhook that allows you to trigger a new compile and deploy when content changes.

Now to host our content for the blog and podcast posts, we are self hosting an instance of Ghost on a Digital Ocean droplet. If you are comfortable with DevOps, you can easily spin up a one-click Ghost droplet or even a Linux Ubuntu instance to install your Ghost CMS. Once you have your CMS ready, you can use it to manage your content and provide that information via a REST API. Ghost also allows you to send out a POST to a webhook when content is updated.

Finally, all processing like our email newsletter subscriptions and marketing campaigns are handled by NodeJs methods hosted on AWS Lambda. It's a very clean and scalable way to handle external operations that aren't available on static website hosting platforms.

If you want me to detail the steps to hosting our site, or any of the steps above, tweet me at @karlclement and I can share that with you.

The Rest

The last pieces are mostly marketing tools for analytics and email communications. In order to make things as scalable as possible, we decided to use AWS SES (Simple Email Service) along with EmailOctopus to handle our email newsletter. EmailOctopus has a great feature that allows you to make your newsletter campaign within their admin interface and send the emails with your own AWS account (which is free up to 62K emails per month).

AWS Lambda functions handle our newsletter subscriptions and segmentation. We can also enhance these tools to later include more A/B testing and customer service. Analytics are stored and monitored using Google Analytics, Plausible, and Hotjar. This gives us a great view of how our visitors are using our website and what content they prefer to explore.

This concludes the list of all the tools we have used to deploy our latest build of wearedignified.com. If there is anything you want me to go into deeper detail or other subjects I should cover, please feel free to tweet me @karlclement