lego, not yet another Static Site Generator
Tags: javascript, sideprojects
Published: 2019-10-05 08:04:59

I have been working for over a year on lego, a static site generator written in JavaScript. When I decided to rewrite my site, I had a wide variety of SSGs to choose from. I eventually narrowed down my choices to the following:

-   **Gatsby** - I really liked how optimised the output was with Gatsby. The only issue I had with Gatsby was the slow build timings.
-   **Hugo** - I loved Hugo for its speed. However, the templating language was frankly too disappointing.
-   **Jekyll** - This was fast enough for my site's size and the templating language, Liquid, was pretty similar to Jinja2. However, doing Gatsby like optimisations was challenging.

I had way too much free time on my hands so I did what every bored developer does. Write my own framework. In this case, I decided to write my own static site generator that emulates the good parts of these three frameworks.

I had a few requirements out of this and decided to try building it for a week or so and see how feasible this was.

-   Support Liquid(recently added Nunjucks support).
-   Support Markdown posts, data in YAML(later extended to JS and JSON).
-   Transpile and uglify JS with terser, use PostCSS for CSS(both use `browserslist` to determine targets).
-   Revision assets like JS, CSS and images.
-   Optimise images.
-   Extract and inline critical styles with [critical](https://github.com/addyosmani/critical) for all pages.
-   Minify HTML of all pages.
-   Generate a tag-wise listing of posts. For example, `site/tags/javascript` should list all pages tagged `JavaScript`.
-   Live Reload during development.

Surprisingly it turned out pretty well. There were still a few rough edges but I quickly ported over my site in the hopes that I could fix them.

*This is when the fun began*.

lego was taking about 5-6 seconds to start up. While this was not that bad compared to Gatsby, I wanted to squeeze out as much performance out of it as I could. The whole purpose of this project was to learn something and have fun in the process so I decided to profile lego. A few interesting things stood out.

-   Just requiring PostCSS plugins was taking a second or two.
-   Some code paths were running more often than necessary.

After fixing these, it came down to about 2-4 seconds.

This is when I started looking into caching. While coming up with a technique for this was challenging, the actual [implementation](https://github.com/astronomersiva/lego/blob/master/lib/utils/cache.js) was rather trivial. After implementing caching, I felt satisfied with this whole endeavour of writing my own SSG. I now had a fast, performant SSG that generated an optimised site.

Right now, lego starts up a development server for my own [site](https://siva.dev) in under 600ms. Rebuilds take under a couple hundred milliseconds. Production builds take about 20 seconds!

I wrote a benchmark to test all this. When Liquid templates are used, lego is about 1.5x faster than Jekyll and when Nunjuck templates are used, lego is a cool **8.7x faster than Jekyll.**

I then added a few more things like RSS Feed generation and sitemap generation based on my own needs. While lego supports auto-generating responsive images, I think it's a little less robust and I will start paying attention to it in the coming days.

If you are feeling adventurous and want to try this out,

-   Run `npm i -g @astronomersiva/lego`.
    
-   Generate a site using `lego g my-awesome-site`. This will generate a dummy site.
    
-   Run `lego s` to start the server.

You can also checkout the code on [GitHub](https://github.com/astronomersiva/lego/).

Have a great weekend folks!