Thanks for visiting my blog!
I’m trying something different. I have a few sites that I manage with just information data (e.g. my film sites, and my company site). In the past couple of years I’ve been creating some of them as raw HTML and just hosting them in nginx containers since they’re simple and tiny.
But managing all the pages via hand-editing HTML is sometimes a pain. I recently took one of them (my company site at http://wilderminds.com) and try my hand at using a static website generator. My experience was pretty great. Let’s talk about that first.
Static Website Generators
There are a lot of solutions for building websites with static website generators. The idea here is to allow you to use some format (e.g. markdown is popular) and have every page on the site generated.
What this means is there is no back-end – just flat files that are served. After writing back-end website code for so many years (“ISAPI filters” was one of the first technologies I used) I scarcely remember creating websites without a back-end.
But before you can do this, you have to think about developing a site differently. If your site really is pretty static, then it is a simple case of generating the code with one of the many options (I’ll talk about these in a minute). But if you need anything more than that, you have to think about it differently:
- How do you send emails?
- How do you provide site search?
- How do you handle authentication?
Creating static websites are usually paired with a set of APIs (e.g. Azure Functions, AWS Lambda, hosted ASP.NET, Node, etc.)
For this article, I’m going to focus on the generators, not the API options. In some cases you can get away with using hosted services (e.g. I used Algolia for search on my blog) for many of the solutions, though for email you’ll likely need to stand-up your own API to support it.
The Contenders
- Gatsby (JavaScript & React)
- Next.js (JavaScipt & React)
- Hugo (Go)
- Jekyll (Ruby & Liquid Templates)
- Nuxt (JavaScript & Vue)
- VuePress (JavaScript & Vue)
- Eleventy (JavaScript & Liquid or Nunjucks)
- Scully (TypeScript & Angular)
- Statiq (C# and Razor)
- (and tons more)
I dug into a number of these, but I’ve mostly used Statiq and Eleventy. But, in general, no matter what you want to do, most of these will work. It more comes from what you’re comfortable with.
I first started digging into Statiq because the .NET Foundation’s website uses it and if you are comfortable with C# and Razor, it’s a natural match.
But the one I will show you is Eleventy as it feels like the one with the fewest moving pieces. It’s just JavaScript and I’m using Nunjucks for templates (though you can also use Liquid and other template engines).
Starting with Eleventy
Since I’ve been playing with static sites, I decided to walk you through some examples with Eleventy. Eleventy is JavaScript based and you can start incredibly simple.
To start out, you just need a packages.json:
> npm init -y
And install Eleventy:
> npm i @11ty/eleventy --save-dev
Now just create a quick markdown (or Liquid or Nunjucks file if you’re familiar with them):
# Hello World
This is the first file
Now just run eleventy to build the site:
> eleventy
This results in a minimal .html file in a _site subdirectory:
Lastly, let’s use some data. You can add front matter to detail some data about a file (in yaml):
---
title: Hello World
date: 2021-05-05
---
# Hello World
This is the first file. It was created on: {% raw %} {{ date }} {% endraw %}
Notice the double curly braces, we’re using data binding from yaml to insert into the document. Though in this case it isn’t that important. Let’s run this in a way that we can change the project and continue to build by asking Eleventy to serve the files in _site:
> eleventy --serve
This results in compiling the page(s) and serving the files (and updating them as you make changes):
Let’s tackle one more idea, layouts. If we create a directory called _includes, we can then create a layout called main (name it ‘main.njk’) which is a Nunjucks file that will allow us to use HTML and some other special things if we need to later:
Now we can just use HTML to build ourselves a super-simple layout page. That means a page that our individual pages will inject themselves into:
<html>
<head>
<title>{% raw %}{{ title }} {% endraw %}</title>
</head>
<body>
{% raw %} {{ content | safe }} {% endraw %}
</body>
</html>
Notice that we’re using that same double curly-brace syntax for injecting the title of the document (from the front matter of our main file) and the ‘content’ is where our documents will inject themselves. We can then just add a front-matter line for layout and it’ll find it for us:
---
title: Hello World
date: 2021-05-05
layout: main
---
# Hello World
This is the first file. It was created on: {% raw %} {{ date }} {% endraw %}
Starting your project like this shows you how you can start static rendering really simply. I’ve actually had good luck using a template that you can just fork in Github (or download) to start your project that has many of the boilerplate pieces already setup:
This template has some basic utilities included, structure of the site, and webpack building of your JavaScript. I think it’s a sensible place to see how a larger project might work or as a starting point.
Last Thoughts
The idea behind statically generating your site means a performance increase (generally) versus server-rendering, but it does mean having to think about web development in a very different way. But of course, if you’re building APIs and SPAs for some amount of your website, then building each of these pieces separately and having them come together in the browser makes a lot of sense.
It is certainly not a perfect system, but if your building sites where this makes sense, I see this as a great alternative to using a CMS for dynamic websites and writing raw HTML for simple projects.
In fact, if you’re reading this story, you’re seeing my Eleventy-powered static website working. In the next couple of days, i’ll be releasing a video showing how to get started deploying the static site in Azure!
What do you think?