What is a static site generator?
A static site generator takes some input files (i.e. templates, themes,...) and data (i.e. flat markdown files or headless WordPress) and produces static files such as html, css, and javascript. You can then host the site just about anywhere for quite cheap or free. The advantages of this method is better security, a faster website (because you have no database to query) and you can deploy the site easily to a CDN (I recommend netlify). In this post I will evaluate several ways to generate a statically generated website or blog. I used Wordpress and Joomla for several years before switching over to statically generated sites for my bloggin needs. I like the control and simplicity of this setup much better. For a comprehensive list of many of the static site generators out there see https://www.staticgen.com
Roll your own
Writing my own static generator was much more simple than I initially thought. I am a big fan of the Flask web framework for Python so I will use that. I really like the control and understanding of the system I gained from writing my own generator. Since I am writing everything from scratch it is easy to customize exactly how I want the generator to behave. Sometimes I want to do some specific routing or layout and the other static generator frameworks limit my control. I end of spending lots of time configuring and overwriting the default behavior.
The default Flask templating engine Jinja is my favorite template system. Hugo uses the Go templating system which I really don't like. I have also tried other templating systems such as Jade and Embedded JS and I always find myself missing features in Jinja such as inheritance, filters, and blocks. I was happy to find out that Mozzilla ported Jinja to JavaScript with Nunjucks. I am definitely using Nunjucks for my next NodeJS project.
A simple implementation in Flask takes less than a hundred lines. There are two key parts to making this work. The Flask plugin Frozen Flask will traverse your application and create static assets. The other key part is the custom markdown filter applied to the Jinja templates.
from flask import Flask, render_template
import markdown
from flask_frozen import Freezer
app = Flask(__name__)
freezer = Freezer(app)
app.jinja_env.filters['markdown'] = lambda text: markdown.markdown(text, extensions=['markdown.extensions.tables'])
@app.route('/posts/<string:title>/')
def posts(title=none):
if title != none:
md_text=""
_file = '../posts/' + title + ".md"
with open(_file) as fout:
md_text = fout.read()
return render_template('posts.html', md_text=md_text)
@freezer.register_generator
def posts_generator():
yield '/posts/my-first-post/'
yield '/'
freezer.freeze()
The template posts.html
with the filter would look like:
<html>
<body>
<div class="content"
{{ md_text | markdown | safe }}
</div>
</body>
</html>
Go to Flask Static Gen to see a minimal working example. Of course this is just a starting point. There are other features that would be nice like an such as an RSS feed and the ability to tag and categorize your posts.
Pros
- ability to customize everything
- gain understanding of the system and technologies involved
- make you a better programmer
Cons
- you have to do everything yourself
Gatsby
Gatsby markets itself as a website compiler. The main technologies behind Gatsby are React, Webpack, and GraphQL. There is a large community around React so figuring out how to do something is quite easy or it has already been done.
Gatsby feels a bit more raw than some of the other static generators I have used. It is definately a developer-centric framework. It requires a bit of programming and configuration to get started. It is somewhere between the Flask way and Hugo for blogging. You can't simply download a theme and start using it. If you are a developer comfortable with React and puting all the pieces together this method is great.
One excellent feature of Gatsby is that is uses GraphQL to pull in data. GraphQL allows you to pull in data from any source like a headless Workpress installation or static markdown files. If I were building a blog for a client I might go this route. You could give the client the nice Wordpress user interface for creating content but only have to worry about deploying the static assets.
Pros
- GraphQL
- turn blog into React web app
- super fast website out of the box
Cons
- cannot create posts with CLI
- remark (Gatsby's default markdown renderer) currently has no easy shortcode support. There is this plugin; however, it would take some work to get it all hooked up. This would be a good future Gatsby plugin.
- No "themes." However there are Gatsby starters to get you going. Not as easy as starting with Hugo or Wordpress themes.
Hugo
I have used Hugo for this blog, my piano website, and the documentation for a project at work. For the documentation Hugo worked out great. It was easy to bring new team members up to speed on how to update the documentation. Hugo is easy to install and all they had to do was edit the existing markdown files or create new markdown files using the Hugo CLI. We did have to work around how Github publishes its pages. Github will serve anything found in the docs
directory of the repo. If you want to use Jekyll you can place your Jekyll site there and Github will build it for you. Since all the developers are using Windows and setting up Ruby is quite painful on Windows I ruled that option out. The solution was to create a separate directory to host the Hugo files and then at release time we build to site and commit it to the docs/
directory.
Some of the features I love in Hugo are the shortcode feature and its great command line interface. If I am writing a post and want some special html button thing I can create a shortcode easily and use it in the markdown. To start a new post use the CLI by hugo new post/my-new-post.md
and Hugo will use the archetypes template file to create a new post ready to edit.
The Go templating language is not as nice as the other two. It feels very counter intuitive. Jinja and React templates feel just like writing Python and JavaScript. Perhaps if I knew Go better the templating would not feel so difficult. Having written a theme from scratch in Hugo I still have to look up the syntax for the templates. The parameters for functions are also very finicky. Somehow the format string for dates "Janurary 6, 2016"
doesn't parse but "January 2, 2006"
does.
Hugo also includes an extended markdown parser called mmark. It allows for tables, letter ordered lists, figures, citations, including files, latex math (provided you have MathJax or Katex support for your website), and more. See the full mmark spec.
Pros
- shortcodes
- mmark
- awesome CLI
- lots of themes Download a theme and start blogging.
- hot reloading development server with
hugo server --watch
Cons
- Go templates somewhat painful
Conclusion
For now I will continue to use Hugo. However, Gatsby seems to have a lot going for it. Learning Gatsby would also be a great excuse for me to learn React.