From static site generator to static site processor#
My website was in a state of rotting for a year, but I'm finally happy to report it's fixed now! The various changes made will allow me to write, update and publish way more easily than before.
It took some time as I felt kinda stuck in the clumsiness of the project. It had become a mix of JavaScript for the data processing and page generation ; and of bash scripts for tasks related to assets and development. The whole thing was failing very often, to the point I was not feeling any joy using it. If you've not been following for a long time, building this website has been one of the joyous experiences of my career on the past 3 years, so I felt terrible to have this playground kinda broken.
I needed a change of mindset. I already had several JavaScript modules for parsing my text files, my markup language, processing data from them. I wanted to continue to use those modules, as I think they are the real value of my project. They reflect how I work and think, they are representative of my journey.
Then, I thought about what constitutes a personal static site generator, and came to the conclusion it's not what spits the HTML and CSS, but the data processing happening before the generation that delivers an array of items that will be turned into a website. Maybe I should not do a full static site generator, but a static site processor that delivers data that can be transformed into a website.
This way, I could continue having fun by plugging new ideas into my brain machine, and disregard the actual generation of files, the optimization of assets. But as a web developer specialized in coding interfaces, I cannot not care, I have standards. I want a fast, cohesive, fun and accessible experience. And for this I need tools to process the parts that I don't want to manage myself anymore.
Finding a good HTML printer#
So I decided to look again at existing static site generators for Node. To please me, it had to satisfy those needs:
- It needs to be a basic HTML printer, not a framework with front-end libraries.
- It must be opinionated enough on its tool chain so I don't have to add config files to process assets and pages.
- It mustn't be opinionated on the data source and allow pre-processing of the source files.
- Easy to maintain, update and run.
And of course, I found nothing. Eleventy is probably the closest to my needs, but it still hasn't migrated to ES modules ; its documentation is complete but somehow, I find it confusing and messy and can hardly find what I'm looking for ; and you still have to configure a lot of stuff for the assets processing, thus are stuck in the fabulous world of the JavaScript ecosystem.
I was disappointed for a few weeks, until I saw Baldur talk about its experience with Deno. Deno is a JavaScript runtime equivalent to Node, but with several differences that instantly satisfied my laziness:
- It has its own shell to run scripts which makes it environment independent.
- There's no package manager, just imports using URLs, so no
node_modulesmadness (but you can store your modules for offline use if you want). - Its JavaScript API is the closest as it can be to the browser JavaScript API, which is good to me as a front-end developer.
- It's a full tool chain that comes with a linter, a test runner, a formater, so there's no time wasted on this.
- It has a no-dependency external stdlib for more complex needs.
And it turned out that Óscar Otero, who really enjoys Eleventy, made its own version of it for Deno, called Lume. It follows Deno principles of being near zero configuration, non-opinionated about the source of data, and comes with a set of official, easy to use plugins, and a clear, concise documentation.
I grabbed my modules, made them even more modular and oriented towards data processing, and connected them to Lume through the config file, and it... worked. There isn't a lot to say, I just imported the modules I needed, configured the process and copy for the assets ; created a for loop into a template file ; split my template into layout partials for more clarity ; and the website was generated.
Simplifying the project#
Seeing this tooling part was done, I could then go back to what I wanted: fixing stuff in my static site processor, ease the writing and modifying of the website.
Here's a list of changes for the data processing:
- The builder can now take several content files instead of one, which should allow me to group content in separated files. For example, I could group all the journal entries into a single file, or use a file per page if I wanted. I really like this flexibility.
- I added creation date to all posts. With my website in this current form turning 4 years old, I felt some pages needed time contextualization. Some information could be outdated, and dates help to make sense of what you read. I did not have any dates prior to this, so I used the git history to catch the oldest commit for each page, and updated the content files.
- I also added a generation date, updated when the content changes. This part isn't perfect, as it uses the live RSS file as a source of truth and compare markups, not the content itself. Inline markup changes (for example image sizes) can then trigger a date change, but that's a sacrifice I'm OK with. This part was the trickiest to get right.
- Added the ability to exclude pages from the RSS Feed. Since some pages are just automatic listings of other pages, they did not provide any value for RSS users and polluted their feeds without giving anything valuable when updated.
- Redid the whole RSS feed in ATOM, as I felt its specs made more sense to me.
For the design and tooling:
- The design system powering this website was a different project in a different repository. Each time I changed something I had to open it, make a change, then move the processed file into the SSG. It made me mad every time, so I imported all the CSS files inside Lume, it processed them without trouble, and I can now experiment live with my CSS in a single place. I'm also porting the design system documentation on the website.
- The templating that was done in my modules is now almost entirely done using nunjucks files. I like nunjucks, it's an easy to use and understand syntax.
- I removed the icons from the footer. We are so used to use basic icons for everything that I never questioned the fact they did not fit in the style of the website. And text is more clear for readers.
- I moved the configuration panel to the footer instead of the main menu. I felt it was out of place, as the other elements of the menu are navigation links.
- In the configuration panel, I removed the ability to change fonts. I initially added them for accessibility purposes, but this effort was misguided. You can read more about fonts and accessibility in this research.
- Drastically reduced the size of fonts from 300kb to 65kb using sub-setting. It's the only thing I could not fully automate as it takes a lot of time to scan the site.
- Fixed image generation sizes to only three: mobile, desktop, full-size. Visitors on mobile should have a better experience now. Also I don't have to run a separate script and it takes way less time after caching.
- Fixed a lot of small visual annoyances and bugs, most you probably never noticed.
I'm probably forgetting a lot of stuff, and I still have many things left to do.
I'm happy to be in a place where it's now possible to just open my code editor, write or code, save and publish without stressing about something breaking.
Again, many thanks to all the people who created the tools I'm now using, especially to Óscar Otero who created lume.