1. 8
  1.  

  2. 4

    Ok, what follows is an advertisment for my own project (soupault), but the reason I started that project three years ago was stumbling upon the same limitations of existing SSGs, only I didn’t settle for Jekyll because Jekyll couldn’t really do what I wanted either. Here’s a comparison table with Hugo, Zola, and Jekyll.

    I’m not claiming it’s perfect for everyone’s use case, but it does allow the user to do many things that other SSGs could not do or required serious compromises to be able to do. Like, for example, mdBook has built-in support for testing Rust code examples, but soupault is easy to configure to do that for any language.

    On the one hand, Hugo provides the convenient .TableOfContents variable at the cost of control, unlike Zola, where we had to do it manually.

    And soupault can generate ToC for every format with the same functionality (where in Hugo it varies from format to format because it’s a feature of the Markdown/AsciiDoc/etc. processors). It can also preserve id from <h2 id="my-section"> and create fully-persistent anchors.

    I have to give Zola credit there: it does provide a ToC data structure rather than a variable with HTML source, so you can render it as you like it. However, the cost is that it only works for a single Markdown flavor that it supports because that ToC extraction is a feature of the Markdown library. Soupault gives you a ToC dict regardless of the source format.

    Looking at Jamstack’s ranking of SSGs, we see that Hugo is the only compiled program anywhere near the top

    What if I were to tell you that native code SSGs can also be extensible? ;)

    I’d discovered it was possible to render maths offline, so no JS would need to be loaded, but this couldn’t reasonably be done with Hugo

    Soupault can filter any HTML element content through an external script and insert it back, so static rendering with KaTeX is trivial.

    A minor annoyance is that kramdown, Jekyll’s converter, insists on parsing the HTML I write, but isn’t very good at it

    Parsing HTML behind the scenes is much more common than one would think. Hugo does it with regular expressions in some places and with a bundled HTML parsing library in other parts. The best ToC plugin for Jekyll I could find used Nokogiri, which is correct but notoriously slow.

    That was what made me think that the right solution to many problems is to always parse HTML and automate offline manipulation of element trees.

    1. 3

      On the other hand, Hugo doesn’t use block-based templates and hence lacks a nice inheritance system like Zola’s.

      This is not true. Hugo templates inherit from a file called baseof.html if it exists. Go templates can inherit from arbitrary other files, but it’s at the Go level, not the template level, so you do it by in Go writing template.ParseFS(tmpls, "base.tmpl", "override.tmpl", "end.tmpl"). Hugo then has to just decide what inherits from what on its side, since it can’t just have the templates inherit from each other automatically by doing the equivalent of {{ extends "override.tmpl" }}. It’s not much of a limitation if you’re doing server side Go, but trying to use it in a framework like Hugo is tricky since it has to be predefined.

      Anyhow, I use Hugo every day at work. It is super-powerful. You can do more or less anything with it if you get clever enough. But I have a hard time recommending it to others because the documentation has completely lagged behind the implementation. The only way to know how to use Hugo today is to have started following the releases in 2016 and adapt whenever something new was added. Baseof is a core concept, but God only knows if the docs will ever tell you that.

      1. 2

        But on the upside it supports plugins at all, thanks to being written in Ruby, an interpreted programming language, unlike its compiled competitors.

        This is a very core thing. If you want something to be maintainable over time, you need to ensure that SSG has some form of eval, so that, if the need comes, you can write a bit of custom code to do exactly what you want,

        I also recently migrated my blog from Jekyll to a bespoke script. I wasn’t quite happy with Jekyll due to dependencies (bundler upgrade couple of years ago broke something, I am in general confused between gem and bundler, with my latest lockfile there was some depreciation warning of something, and running Jekyll required compiling some c++ for something called eventmachine, which is not fun on nix).

        Now that deno and modern JS with string templates are a thing, and Djot is almost a thing, I can finally write a simple self-contained script to slurp my prose and spit html which I am confident is not exposed to ambient dependencies from my OS.

        Scripts’ entry point: https://github.com/matklad/matklad.github.io/blob/master/main.ts

        1. 1

          As with favorite editors and config management systems, the choice of which SSG to use is less important than the impact of using one.

          1. 1

            I rolled my own SSG for my blog because I couldn’t find any that minified fonts (by removing unused glyphs). The generator is a bash script that uses pandoc to convert Markdown into HTML, although it could use my KeenWrite software instead. There are two scripts:

            • The build-template, which simplifies writing user-friendly scripts. This is required to run the build script.
            • The build script, which generates navigation, RSS feed, minified fonts, HTML, etc.