Lately at work, we decided to move our code library (old version) to a new tech stack. Up until now, we used our data platform to mimic a CMS: we had a dataset (in JSON) where fields were our site’s content. It was a fun use case and we could leverage some in-platform functionalities, but it quickly grew impractical. The flow to add new articles was clumsy and complicated, the "dataset" we produced was useless as such, and, most importantly, we had little to no preview of the content before shipping to production.
The code library we wanted to build is pretty simple: read-only content with a live demo of what you can do on the Opendatasoft platform and some code for you to copy. This sounded like a perfect fit for a static site generator. So off we went to choose one!
- The ability to quickly add pieces of content with very similar formatting, including adding blocks of HTML and CSS code with text descriptions around it. We favored MD, but WYSIWYG was also an option.
- Be able to copy the code to clipboard and edit it on Codepen
- Have a quick dev mode to correct typos with a live preview, without having to re-upload everything.
- All sorts of filters by sections and tags, as well as a search field to find resources.
- Simple hosting. We didn't want our DevOps team to set up complex deployment pipelines for a side product like this.
- The only front-end framework—if any—should be React. The frontend of our platform and some soon-to-be-released wrappers are already using React. We didn't want our users to have to load two libs, neither did we want to scatter knowledge internally.
So let's see our contenders of the day!
You've read React and Static Generator: you're thinking GATSBY. You're thinking it so loud I can hear you from France!
Well, no. When I saw this kind of boilerplate for rendering Markdown, I didn't even bother trying it. Gatsby might be extremely useful for large editorial sites with many sources (e.g. fetching from a headless CMS and social sources) and complex UI. However, for primarily rendering Markdown on simple templates, it felt over-engineered. (Why people use it for blogs is beyond me…)
The wrong assumption here would be to think that because our site would include “some React”, JSX had to be our main templating language. However, we may really only need to render React components, nothing more. For this, we could just include the lib in the header and the JS files for the components in our assets,, and we would be just fine. It's not because you use a little React for rendering that your site is React SPA.
While we really needed markdown files to be as easy to add as possible, our UI needs were really simple.
NextJS (Nuxt, Sapper, Gridsome etc.): Same conclusion, but it might be more obvious since it is more "app" oriented… or at least more marketed as such.
The problem is—which is part of their strength as well—that they are geared toward very specific layouts. The more you want to diverge from it, the more painful it is. Sadly we had to diverge quite a lot.
I was very excited about 11ty. It seemed simple enough and very flexible, with good filtering abilities. The ability to choose your templating language and folder structure was also appealing. Sure, it also came with that simple
config.json which would have probably grown into a new lifeform of its own—as they always do. But fair enough, let’s try anyways.
Yet, in my test, I realized with that freedom—e.g. in your folder structure—comes the freedom to botch up. For example there are many ways to implement internationalization: folders, file extensions, etc. However, my colleague and I came up with different solutions for the same thing. While it suits the little choices you have to make everyday, you will have to make sure you document conventions for your colleagues. This can end up being pretty confusing as everyone will start using their own clever tricks. Other brilliant ideas, such as template cascading, fall into the same trap.
The second thing was performance. Live reload wasn't fast on a test site. I can only imagine what it would have been on hundreds of resources with a variety of assets. I also had to ctrl+c much more often, e.g. for any config change.
Overall, 11ty seemed fun, but too brittle. I will definitely tinker with it on personal projects. For professional use though, the risk of being stuck in a dead corner seemed too big.
Hugo isn't new or exciting. But it's fast, it does everything we need, it's stable, it's alive, tested and proven. Taxonomy? Tags? Built in. Speed? Lightening fast. Markdown support? World class leader. JS? The pipe is fast and reliable. Got a problem? Somebody probably had it before you and likely there is a solution hanging around on the Internet.
While it may seem a bit rigid at first, there's hardly anything you can't do easily. You have to conform to the Hugo way of doing things though, especially in your folder structure. In our case, that was a blessing. Sure, you have to learn it, but there is a single source of truth and it is documented.
Go templating may seem a bit alien and inelegant at first, but it's easy enough to learn. And while I still find it slightly inelegant, it is very efficient. Years of trial and error have made the team add quite a lot of functions. Really, it's hard to find something you can't do with Hugo.
Making your templates and archetypes is straightforward, as well as maintaining them. We have been able to easily build a system where, from a single source of html and css, the code to read and copy is generated, the result rendered in an iframe and the user given the opportunity to open it using codepen.
Now along with the *.html.inc and *.css.inc files (.inc because they are not meant as standalones), we only need a single file such as this one in the same folder :
--- title: "Dropdown module 1" --- ## Basic example
A very basic HTML so that you can see how the component works and to be able to edit it easily.
As you can see, once you have good templates and archetypes, it's straight to content. We had over 50 resources to migrate and the process was overall quite smooth.
We tried both fuse.js integration and Algolia for search. Fuse works excellently, but you do have to redesign all your search boxes from scratch and, more importantly, define all the weighting and sorting yourself. So we went with Algolia, although we ended up doing a decent amount of redesign on top of it. Still, it works more automagically than fuse.js.
Bootstrap still came with quite a few libs to load and is quite monolithic. Tailwind's tooling is quite complex and, as quick as it may be to build with it, I had serious questions about maintaining code build this way.
In the end we went with Bulma and couldn't be happier. It's pure CSS, very simple and extremely well-written. The fact that it's tuned with global variables was the killer feature for us: our designer gave us specs (from a design system) and we could implement it quickly and make the whole site very consistent.
We liked Bulma so much that we are beginning to inject it into other projects!
One major concern was accessibility, especially for Nicolàs! Components such as tabs, modals or show/hide functions can be quite long to implement l. We could have rewritten everything ourselves following best practices, but the more JS and CSS you add, the more complicated it gets.
Fred found quite a nice library with http://van11y.net/. It's not rocket science, it's nothing we couldn't have done ourselves. We were even a bit dubious at first because it is almost five years old! Can you imagine that? Yet it works and its pure ES2015. The reason why it has never been updated in the last five years isbecause, well… it works.
Check it out, it's pretty neat!
I love tinkering with techs, libs and apps on my personal projects. You break things, you re-build, re-break etc. There is nothing at stake besides learning and having fun. Yet it was the first time I had to do this professionally and the stakes were quite different. Our resource site is nothing critical, it's not the end of the world if some CSS breaks: we can hotfix it. Yet, I didn't want it to become a burden, consuming bandwidth, for me and—most importantly—my colleagues, everyday.
Hugo, Algolia and Bulma might not be hot or “groundbreaking, but it's an excellent choice for this reason. It's nothing we can brag about during coffee breaks. There is no clever solution we had to develop that will give me some DEV street cred'. But we were able to save valuable time. During development, Hugo practically disappeared. We spent very little time searching for"how to do this in Hugo" and we spend the vast majority of our time actually building the website. This sentiment was only reinforced when I had to leave for one month. When I came back, everything was running smoothly, with no complaining about the tech stack.
There is a second lesson here: our solution involves very little JS. Resources on the web tend to involve tons of JS—because there is a big audience for click-bait Build this app in 10 easy steps tutorials. Yet, for content-first sites, it can remain minimal and it is possible to build very modern websites without transforming your
node_modules into a black hole.
So ask yourself twice: do I have complex UI needs? Am I overwhelmed with state management? Do I need to fetch data from multiple services? If the answers are no, no and no, Hugo is as solid as it gets–and probably more!