The big upshot of Jekyll for me is that I can use Ruby plugins, and that Ruby allows me to do Crazy Stuff™ with monkey-patching. This means I both have a "works out of the box experience", but that I can also tweak and customize anything I want, or add new features in an "ad hoc" fashion when I need them – it's the best of both.
This isn't possible with Go, because it's just not that kind of language; it's more or less impossible to have a plugin system similar to Jekyll.
My dayjob is to write Go code and has been for almost 8 years, I think Go is a great language. But I don't think the language is a great fit for this kind of thing.
Genuinely curious, what kind of Crazy Stuff do you need for a static site generator? It strikes me as one of those technologies I want to be as boring as possible. I never want to debug why my content is not being rendered.
If you want "as boring as possible" and "never want to debug" then you probably shouldn't be using Jekyll in the first place; for simple boring use cases all you need is:
for f in ./posts/*.md; do
dst=site/$f:r.html
cat head.html >$dst
markdown $f >>$dst
cat footer.html >>$dst
done
Or some variant of that, in your preferred language. There's loads of things you can do wrong in Jekyll even without any plugins, and this applies to most static site generators.
Anyway, I have a list of plugins at [1]; some are as simple as "don't use leading 0 for dates but a space" so it looks nicer (IMHO) but still aligns well, and others are a bit more crazy such as "use Vim's :TOhtml for syntax highlighting because I think Rouge looks horrible".
Stuff like "show all posts with the same tag as the current post" could be done in pure Liquid template too, but this is usually a lot more awkward and a lot slower, and convenience tags like {% warning %}Watch out!{% endwarning %} are completely unnecessary as such, but it's just convenient and nice.
Oops, the :r to remove the extension is zsh; I'm so used to writing scripts in it I sometimes forget translating it to sh/bash (should also quote the variables in (ba)?sh).
both of these scripts break on perfectly valid filenames with whitespace, it's pretty rough how shell scripting directs you towards writing subtly broken scripts.
Perfectly valid file names in your case can be quite poor choice of names in the context of generating static site. And even if the code could be perfectly runnable, I expect them to be pseudo-code here to illustrate a point, not to ask people to run it.
It's just an illustrative example that I didn't even bother to check for syntax errors, and I'm just used to zsh syntax so I don't always remember to translate to POSIX, and quite frankly, it doesn't matter because no one will or should run this script, because it's just illustrative, which is obvious to anyone.
> Typically this term refers to a rhetorical strategy where the speaker attacks the character, motive, or some other attribute of the person making an argument rather than attacking the substance of the argument itself.
Customised markdown snippets, various semi-dynamic data fetching and preprocessing (eg churning a database into JSON for a front-end), chunking MPA bundles based on the pages, etc etc etc.
Ways to [ab]use SSGs to fulfill your twisted whims are legion.
I second that the hackability of using a tool written in an interpreted language is a huge advantage, but Jekyll can be darn slow and with Hugo (written in Go), the need for plugins is actually quite low in my experience - thanks to "shortcodes", Go templating, and render hooks.
If you want to customize the Markdown parser or similar, it requires to change the Go code and compile everything yourself, which is not great especially from a maintenance perspective. But I wonder, would it be possible to add more extension points and then only compile plugins written in Go instead of the full source code of the tool plus your modifications? IIRC, Go does support something akin to shared libraries but not cross-platform.
I completely agree. The go templating language is a nightmare. I probably learned most when dealing with Helm, but I've always been holding out hoping that something better would replace it.
Does anyone know why the templating situation is the way it is in go? In many other languages you have multiple competing templating languages, but in go this is basically what you get. Are there language specific features that make it hard?
EDIT: interesting to final see active liquid templating engines for go. now if only legacy would allow for the use of these things.
My opinion is that helm does the completely wrong thing: patching text. It should instead patch objects, so that we don’t have to deal with indentation and other silly things.
I'm completely with you. Generating a data structure using a text templating language is just awkward and error prone. In fact I'm starting to think that text templates are very rarely the best option. It is usually better to have a proper emitter library or AST data structure that can be generated with "real" code.
I guess one of the few places that text templates can provide value is when the template is untrusted. But maybe a sandboxed programming language is still a better option here.
I have migrated from Jekyll to Hugo for my own website, but the whole Hugo project is just weird. It took me like a year to migrate my simple website because of all the different paper cuts that drained my will to work on it.
You are only able to only use partials in HTML pages and shortcodes in Markdown pages. Why? They use 2 different syntax, so the best you can do is awkwardly wrap a partial in a shortcode. What's the point? They serve basically the same purpose.
Want to set up RSS? Oh yeah, for some reason by default it will not show full content in your feed reader, instead only a small extract. The the only way to fix it is by making your own template[1]. But wait, why are we using RSS instead of Atom? Who knows, but if you want to use Atom, you have to use your template and insert some stuff to your config.
Also don't look at the bug tracker, that thing is frustrates me to no end.
You of course have the everyone's favourite Stalebot that you might have noticed in my previous link, but if you look at older issues, you will see the maintainer self-botting as a Stalebot[2][3] for some reason.
You will also see the maintainer moving issues between milestones for years with no end in sight[4]. That's not a one-off, click on any issue.
Changelogs can sometimes feel a bit, odd too:
> but also a big shoutout to @dependabot[bot], […] for their ongoing contributions.
And commit messages sometimes are just… a bit too long[5] (it is truncated by GitHub, you can append .patch to see the full message).
Their documentation is awful to read too[6]. Oh and the templating engine? Yeah, not documented at all. Also the quick start guide will tell you to git clone some random theme, but I don't want my website to look like someone's, I want to write my own styles and have my own structure, but they don't really tell you anywhere how you should go about it. Because of it, I would search GitHub to sometimes find answers on how to do some stuff, but you would quickly find that most people had no idea how to actually use it. For example you can find a lot of people making opening and ending partials to have a common page layout instead of actually using the built-in Hugo layouts.
So why have I bothered switching? i18n support, so far out of all SSG I tried, Hugo does it in the least painful way.
Hugo's documentation isn't good, no doubt. But compared to Jekyll's docs, there's at least a lot of (reference) content. Jekyll's docs feel like a beginner-friendly tutorial, but from there you have to figure out everything else yourself, often requiring you to scour the internet and read the source code.
> I have migrated from Jekyll to Hugo for my own website, but the whole Hugo project is just weird. It took me like a year to migrate my simple website because of all the different paper cuts that drained my will to work on it.
My blog's migration anno took only a few days, including a template creation from scratch. My template is still unfinished unfortunately, as Hugo was missing features I needed for my vision back then, and since then I gave up a bit on blogging because of the papercuts mentioned, and the immense timesink that is creating reasonable quality content for publishing. (I do paper-based journalling mostly nowadays since then).
Recently just reviewed the Hugo changelogs since the version I use, and now it knows everything I need to finish up my blog (especially features around images and internationalization were missing, since my blog is not in English, and Hugo used to miss a lot for tiny stuff supporting non-english sites properly, eg. date string localization, sorting for localized tags, like the 'abc' in my language starts as 'aábc', but á got sorted after Z (yes, capiztal Z) if I recall correctly, making localized tags hard to use.). I had some hacks for some in place, but it was tiresome.
Now Hugo has all the bells and whistles I need, even more than enough... It is hard to wrap my head around the plethora of features and new concepts. I wonder if the docs cover my usecases, or I'll need to do some Sherlock Holmes stuff once again, to get going...
So the takeaway of this rambling? Hugo is great, it is fast, and by now it probably knows everything one can reasonably need. But man, it is hard to learn, it has become a huge topic, as sitebuilding naturally has its depths, just like any other topic, once real life problems are to be solved with it. The docs? Not great, not terrible. Overall I still recommend it over anything else, as the docs are still okayish for basic stuff. I like it, it is a great project. I love that almost every changelog includes that it got faster a little bit. Atypical for current software project. And it is fast indeed. (experience from a 5 year old release) I have worked with some trendy javascript based web authoring tools at workplace, and man they were all sluggish and had way worse developer experience than Hugo, also their docs weren't better at all. (has nothing to with Js apart from being popular nowadays)
The fact that Hugo still doesn't play nicely with Tailwind 3 (2 years after T3 was released) is a real pain point.
I gave up on this ever being fixed quite a while back, but still check on the issue [1] every now and then. Seems like the only activity these days is bep bumping the milestone every month.
> Anything to make static website builds faster is welcome
Genuine question, but why? My assumption here is that builds are infrequent and static sites gravitate towards being smaller in size, and that in most situations you’re building as an automated action following the addition/modification of a page. Does it matter if the build takes 1s vs 20s?
Even dynamically building during authoring, I rarely run into situations where ruby/js static site builders feel overly slow. Curious if my assumptions of how people are using these are wrong however so would love to hear your take.
I have 450 posts and about 300 more drafts with Jekyll.
In development it takes Jekyll 32 seconds[0] to do a full build and I've done my best to eliminate as many performance killing nested loops as possible. If I use --incremental it takes about 3 seconds, so my normal writing flow is to split my browser and code editor and I see real-time live reloaded feedback in 3 seconds.
It's pretty good, but some changes require a full build and waiting 30 seconds stinks. If I could snap my fingers and have a fully compatible Go solution that built it in 3 seconds all the time I'd switch without thinking.
Gojekyll isn't compatible with a few plugins I use and switching ~700 posts, a bunch of templates and a few custom plugins to Hugo isn't worth it for my use case.
On the other hand I'm locked into Jekyll 3.X because I can't get Jekyll-Assets to work with any other version so at some point I'll switch but I'm not looking forward to porting that many templates and posts. If it comes down to it I'd probably end up writing a custom tool to convert everything especially since I do custom'ish things with front matter like create a table of contents for each post. It'll require a bunch of string parsing.
[0]: This is on a 9 year old quad core i5 3.2ghz workstation with an SSD.
My team manages several static sites. They're each hundreds/thousands of pages in size. Here's why we like faster builds.
* Fast builds are way more pleasant during development. "Incremental" per-article builds help, but not in all scenarios. Nothing kills my motivation faster than having to wait 30 seconds to preview a fix.
* Fast builds help us avoid jams in our automated push-live systems. Sometimes we have many editors updating pages during a big event. You could consider many different trade-offs when deciding how to manage these queues. But a fast build time erases a lot of those conversations.
We use 11ty on most of our sites. We've found 11ty itself to be fairly performant. The slugs tend to be everything related to processing assets: JavaScript bundles, Sass builds, image manipulation, etc. By streamlining those activities, we can usually get a site build down to just a few seconds.
That said, "instant build" is the dream that animates the best conversations on our team, and we've started building our own static site generator. Our SSG can run both on the server and in the browser. We want our editors in our CMS to be able to get instant, true previews of the page they're editing. Then we want to be able to push single-article builds live, instead of always rebuilding the whole site. It's early days yet. Maybe you'll see it on a "Show HN" some day.
No, plugins are not supported in any meaningful way. With Jekyll I can write "_plugins/foo.rb" and put any code in there to add new Liquid template tags, new features, change behaviour, and even monkey-patch hard-coded core Jekyll code.[1] I can't do this with GoJekyll, because Go doesn't really provide a good mechanism for this kind of thing.
What it does have is a bunch of optional features that are typically provided by plugins in Jekyll[2], but this is a very different meaning of "plugins" that Jekyll has.
[1]: Whether you should be doing this is a different issue, but I would argue that for a static website builder it's fine, especially since you can just lock the Jekyll version with little downsides, and Jekyll doesn't change that often in the first place.
Context is everything. In the context of Jekyll, all of this is certainly a useful feature: this is not code that needs to be re-used or maintained in the same way as your Rails project has to be.
As always, engage your brain before doing anything and you don't need to use these features, but it gives you the tools to do "smart things" that Go simply can't. This, among other things, means that Jekyll will scale reasonably well with your website as your needs grow, without having to add features to Jekyll core, using your own fork of Jekyll, or switching to something completely different.
For example, I have a little plugin[1] to work around a bug[2] and to skip the hard-coded requirement to have a date in the filename.[3] Is this ugly? Yes. Is this fine to generate a relatively simple personal website? Also yes.
Yeah, in large projects that span a number of developers I agree with you. In a project that only I will ever touch? Like my personal blog? No way am I not going to reach for the most powerful featurea of a language. That sounds like exactly the right place to experiment with them.
> With Jekyll I can write "_plugins/foo.rb" and put any code in there to add new Liquid template tags
To be fair, Hugo's shortcodes are similar to this without requiring a plugin. And with render hooks and `.Scratch` to temporarily store information, it gets you a long way. It takes some time and experimentation to understand these abilities, however, and the documentation is not always helpful, to say the least.
Once there's feature parity, it'd be great to see more functionality added as first class features so that so many additional plugins aren't needed for seemingly common and basic needs. It's sad that Jekyll development pretty much all but stopped and any wanted features need to get shoehorned in via plugins.
I could care less about faster, but I would sure love to switch from Jekyll to something that builds from a statically linked binary.
I only put our blog posts a couple times per year, but it seems that the Jekyll dependencies move beneath my feet and break routinely. This is especially a pain because Jekyll and homebrew are the only ruby projects I work with frequently, and so I'm always at a loss for how to fix things -- rbenv, updating gemfiles, do I need to gem or rake or bundler something, architecture-specific problems with C dependencies, yuck.
For now I just put everything into nix which seems ok, but I think I may make a third attempt at switching to Hugo soon, or maybe this, or maybe cobalt.
I'm glad to hear I'm not the only one who constantly ran into issues with Jekyll. The last time was particularly bad. Even after removing my whole Ruby environment and setting things up from scratch I couldn't get things running again due to mysterious compilation issues so I eventually gave up.
Luckily my use case is super basic (just a personal website with a bunch of my projects), so a good solution for me was to switch to a custom Python script that pulls in liquid and markdown packages and has just enough features I need to generate my site.
I can relate to this. I blog sporadically, using different computers, and every time I had to pull the repo and get it to run, several things would break, resulting in a very painful dependency management process (I must admit that I lacked experience with ruby projects in general).
After porting my blog to Hugo, having a single binary that can perform all tasks on all three operating systems I use (MacOS, Windows, and Linux) is a blessing, and now the blog builds incredibly quick.
With a Gemfile and Gemfile.lock you really don't need to do any of that. The only thing that you will need to do is "bundle install" once your Ruby version is updated, which can be prevented by not updating Ruby. I just locked the ruby version in my package manager as I only use Ruby for Jekyll.
Other than that: if it works today, it should still work in a year, or 2 years, or 5 years.
> The only thing that you will need to do is "bundle install" once your Ruby version is updated, which can be prevented by not updating Ruby. I just locked the ruby version in my package manager as I only use Ruby for Jekyll.
I'm not sure that's a good idea. While you might avoid unexpected updates to Ruby, you'll also avoid security patches for CVEs.
I can also relate to this. As wonderful as ruby can be, my install (or lack of, then install) always seems to break when I get back to it after some time away.
Wait, is this a single binary? If so, that's the big deal.
The only reason I left Jekyll for Hugo was that I could not maintain a working installation because of all dependencies and messy package management in Ruby.
Pretty awesome that it's Bjørn, the Hugo developer that's behind Gojejyll.
I have a blog with hundreds of posts. Jekyll would take multiple seconds to process any change (maybe even minutes for the initial build, cannot remember), so iterating over the final touches of a post was really painful.
Hugo builds my whole site in less than 10 seconds and reloads individual post changes in milliseconds. It’s a game changer while previewing edits.
Yeah, but... surely, when you were iterating on a post, you were running Jekyll with --limit_posts or doing an incremental build?
I agree, it's a nuisance that a full build can take a while (my own site, which has almost 600 posts plus a bunch of other random pages, takes at least 30 seconds for a full build, if memory serves), but it's hardly a dealbreaker.
Jekyll doesn't enforce or validate links between posts. I know this because I build my site with --limit_posts all the time (it's literally part of my build pipeline due to the way I handle webmentions).
Is there some plugin you were using that was blowing up?
It would require full compatibility to be useful. I suppose most users of GitHub Pages don't actually use customization. Gojekyll could be used for building these, otherwise fall back to standard Jekyll.
I believe GitHub Wikis are also rendered with Jekyll? Without customization capabilities on the user side, Gojekyll could be used here, too.
It's really not that slow; my website builds in 0.8 seconds (121 pages) and OP's website builds in ~30 seconds (3,325 pages) – or rather, OP's website can be built in ~30 seconds (see my other comment: https://news.ycombinator.com/item?id=37277381)
All of this is without cache, and with incremental builds disabled; it will obviously be faster with cache and incremental builds.
I don't know where this "Jekyll is notoriously slow" comes from; maybe it was (very) old versions, or maybe it's some plugin people use, or maybe something else, but I've used Jekyll for a number of websites over the last ten years, and I never really had any performance issues.
Certainly today, I think it's unfair to say that Jekyll is "slow". Yes, Go is faster, which should hardly surprise anyone, but for most purposes Jekyll should be more than fast enough, and you'll hardly notice the difference with something faster like Hugo or GoJekyll.
That and faster builds overall, especially with large projects.
For example, the documentation of my MadelineProto project would take more than an hour to compile with Jekyll, compared to a few minutes with Gojekyll.
If I disable that your project builds in 30 seconds (no cache!) on my pretty old and not very fast i5-8350U, which is roughly what I'd expect for a project of this site. It will be even faster with cache, obviously.
I didn't look too closely, but I'm reasonably sure that can fixed so the total build time will be 30-40 seconds without to much effort; it looks like it's just generating the same HTML every time, so just caching it on the first generation seems like the obvious way.
And sure, Gojekyll is loads faster and more forgiving of these kind of inefficiencies, but "a few minutes" still seems pretty slow, especially considering even plain Jekyll can do it significantly faster.
Neat, thanks for noticing, the theme is basically a slightly simplified version of https://github.com/just-the-docs/just-the-docs, never suspected it was an issue with it, I'll take a look to see what can I fix!
I think GitHub Pages only supports a whitelist of plugins, so you might have some more difficulties solving it well without any plugins. I use Netlify for my site, which does support arbitrary plugins.
One quick way to make it faster is to include that "_includes/nav.html" only in a nav.html, and then use an iframe to load that on every page, or something like that.
Some aspects of it certainly are, but it's also one of the more limited templating languages out of the box IMO, and there are several sharp edges especially in conjunction with Jekyll, where it requires you to do all the parsing of what gets passed to a custom tag or filter.
So, no support for plugins. What's the upside then, considering that building static jekyll pages is a solved problem, even if it takes 500ms instead of 90ms?
Thank you for creating this! I’ve been looking for an alternative to Jekyll locally, while also sticking to the Jekyll repo format to use with GitHub Pages. (Because the repo format is good enough, and trying to migrate to Hugo was a nightmare on each of the three attempts I made several months apart.)
I wouldn't call a generator that does not support dates in URLs feature-rich. Zola seems extremely opinionated. Dates in URLs are supported by nearly every SSG out there and it seems quite crucial if you want to migrate from one of those and keep your (cool) URLs.
If I’m getting what you mean correctly, Zola does support that, look for index transparency, add “transparent = true” to your _index.md, this post explains it for adding “blog” prefix [1] but you can do it with year prefix, then month prefix inside, your folders structure will be years, inside it months, inside it your posts, and your URL will be like this “site.com/year/month/title” (I did the same concept as you can see in these URLs [2]), that, or just write the date in your .md file as in “2023-May-some_title.md” like I did in my blog (empty blog, didn’t yet migrate but it explains it)[3]
This isn't possible with Go, because it's just not that kind of language; it's more or less impossible to have a plugin system similar to Jekyll.
My dayjob is to write Go code and has been for almost 8 years, I think Go is a great language. But I don't think the language is a great fit for this kind of thing.