Jekyll doesn't do components? Liar!
09 Sep 2021
Hot take: anyone who tells you that Jekyll doesn’t support component-based design, and that you need a React- or Vue-based static site generator, is wrong.
- Any basic fragment-of-HTML “component” you can define with JSX in a file and then cross-reference as
<MyComponent key="value" />
, you can just as easily define with Liquid in a file and cross-reference in Jekyll as{% include MyComponent.html key=value %}
. - Any basic fragment-of-HTML “layout” you can define with JSX in a file and then cross-reference as
<MyLayout>Hello, world</MyLayout>
, you can just as easily define with Liquid in a file and then cross-reference in the front matter of a Jekyll template aslayout: MyLayout
.
Example
Remember my “what you see is what you get” (“WYSIWYG”) componentized Squarespace-style “site builder” I learned Gatsby so I could build last year?
I didn’t actually need Gatsby – here’s the source code in Jekyll, and ta-da, live site.
(Update: see this same “page builder” for 11ty on GitHub.)
Drag-and-drop
Need to see with your own eyes that it can have a drag-and-drop CMS experience? Click around this theme in Stackbit and see.
Why Jekyll isn’t perfect
Okay, actually, no one’s wrong, per se, and certainly not lying, about newer SSGs (and their templating languages) helping you develop components easily.
I just wanted to point out that componentizing a site so that you can give content authors a Wix-like drag-and-drop experience comes from:
- architecting a data model for that purpose
- architecting your static site generator templating for that purpose
You don’t need a JavaScript-based SSG or a “hydrating” SSG or a “modern” SSG or anything of the sort to do really fancy things with “components.”
“Components” are a way of thinking, not a property of a specific SSG templating language.
However, there are some related problems you might run into like:
The syntax can be heavy
Liquid doesn’t really love objects & arrays – particularly not making it easy to instantiate them as literals.
As soon as you want to pass around particularly complicated structured data, or do any fancy preprocessing of it, the amount of Liquid that you have to write really starts to explode, compared to the amount of JSX or Vue.js templating code (which JavaScript – including NPM package imports – slips right into natively) that you have to write.
But also, the syntax can be light
That said, when you don’t have heavy computation to do, I find Liquid’s plain-HTML-like syntax much cleaner and more concise than React’s or Vue’s templating syntaxes, which is why I’m defending Jekyll in the first place.
Here’s what a basic component looks like in React:
import React from "react"
export default function Home() {
return <div>Hello world!</div>
}
Here’s what that same component looks like in Liquid:
<div>Hello world!</div>
The Jekyll ecosystem is small
It’s not JavaScript all the way down
When you’re using Jekyll, any custom computation you need that exceeds the power of Shopify’s Liquid templating language has to be defined in the Ruby programming language.
I’ll admit, it’s really nice to use one programming language – JavaScript – in:
- The front-end code you deliver to site visitors’ browsers alongside your HTML and CSS (in Jekyll, that’s JavaScript).
- The HTML templating code (in Jekyll, that’s Liquid).
- Jekyll won’t let you randomly call Ruby’s
.map{}
within Liquid template code. You have hand-add Ruby code to the Liquid specification as a “Liquid filter” using Jekyll’s “plugins” functionality. - React/Vue-based SSGs, however, will let you randomly call JavaScript’s
.map()
within their templating languages, because it’s built into the syntax of the templating languages themselves that you’re allowed to do that.
- Jekyll won’t let you randomly call Ruby’s
- Deep-back-end functionality (in Jekyll, that’s Ruby).
NPM > Gems
Let’s be honest, these days all the cool stuff – particularly for supporting web site generation – is an NPM package, not a Ruby Gem. Like libraries that:
- Import content from Sanity CMS
- Render front-end HTML & CSS & JavaScript that embeds a video player into your web site
Content editing tools are scarce
Headless CMS is tough
Jekyll is old, and it doesn’t bake in a presumption that you’ll be fetching external API-based headless CMS data into your build the way Eleventy does.
To use data from Sanity, Contentful, the Notion API, the Wordpress API, etc. you literally have to run (and possibly hand-write) code that dumps API-sourced data into files on your filesystem that Jekyll can understand, before running jekyll build
. (A couple of pre-written libraries: Contentful’s gem, Sourcebit.)
You can 100% build a really well-componentized theme in Liquid, as I’ve shown above. But the whole point of building a componentized theme is to give people a Wix-like experience through a drag-and-drop GUI editor, and most of the good content management user interfaces are built into API-based headless CMS websites.
Few Git-based CMS options
There are drag-and-drop content editors that play nicely with storing your content in the same Git repository as the site’s template codebase, like Netlify CMS and Forestry.io, but they’re not truly WYSIWYG experiences.
- TinaCMS is a Wix-like experience, but it doesn’t support Jekyll. From what I can tell, it leverages the front-end code that newer site generators like Gatsby and Next “hydrate” into the “DOM” to support its drag-and-drop functionality.
- Prismic Slice Machine: semi-Wix-like content authoring experience, but same issue – “hydrating” SSGs only. No Jekyll.
- The only Wix-like experience I’ve found so far that supports Jekyll is Stackbit … but who knows if they will forever? I can’t imagine that adding a live-edit drag-and-drop skin to Jekyll’s
localhost
engine has been easy for them to code, as amazing of a gift to the world it’s been that they figured it out.
Further resources
- Components: Server-Side vs. Client-Side by Sean C. Davis.
- The components (“includes”) in my Jekyll codebase would be considered “Jamstack-flavored” (rather than “server-side-rendered,” which you might call “Wordpress-flavored” or “CGI-flavored”) “server components” in Sean’s vocabulary.
- The components I made for the original Gatsby version would be “hybrid server+client components.”
Sean and I got into a great conversation about specific use cases for making the jump from pure server components to client/hybrid components, and for him, one of the biggest reasons was having a website complexity scope that tipped the scales from “Liquid is awesome!” to “Liquid is so burdensome.” (See “the syntax can be heavy” / “the syntax can be light.”) Even when you don’t actually need any client-ish-ness to your components at all, there simply aren’t pure server SSGs with JavaScript as an underlying programming language that use powerful JavaScript frameworks and don’t “hydrate” your server components into client components. Often times, Sean finds that an enterprise project has to jump from 11ty to Next just to use more JavaScript under the hood – everything else that Next does with hydration is just a side effect, from the developer’s perspective.
Sean also pointed out that while authoring a main.js
bundle isn’t so bad if all you’re trying to do is make one top-navbar pop out properly like I did for My Huong Kitchen, once you have dozens of interactive components rather than one or two, not using an SSG that’s built for tightly coupling markup and interactivity, and using vanilla JavaScript instead of using an SSG whose front-end framework gives you handy interactivity shorthands, becomes death by a thousand papercuts.